[[{"@type":["BlogPosting"],"@id":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/#BlogPosting","@context":{"@vocab":"http:\/\/schema.org\/","kg":"http:\/\/g.co\/kg"},"url":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/","publisher":[{"@id":"https:\/\/www.schemaapp.com\/#Organization"}],"audience":"https:\/\/schema.org\/PeopleAudience","inLanguage":[{"@type":"Language","@id":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/#BlogPosting_inLanguage_Language","name":"English"}],"mentions":[{"@id":"https:\/\/www.schemaapp.com\/entity#Thing2"},{"@id":"https:\/\/www.schemaapp.com\/entity#Thing6"}],"dateModified":"2023-03-20T20:21:09+00:00","headline":"Additive Schema.org Data for Local Inventory Advertising","datePublished":"2017-11-08T15:38:43+00:00","image":[{"@type":"ImageObject","@id":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/#BlogPosting_image_ImageObject","url":"https:\/\/www.schemaapp.com\/wp-content\/uploads\/2019\/11\/Additive-Schema.org-Data-for-Local-Inventory-Advertising.png"}],"mainEntityOfPage":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/","name":"Additive Schema.org Data for Local Inventory Advertising","articleBody":"Scenario\nWe recently had a project that started as a National Retailer wanted to pilot Google\u2019s Local Inventory Advertising (LIA) program. The Advertising program bridges the online and offline world. The retailer, which has 500+ stores nationwide, could advertise products that are in stock locally. If you search for \u201cBauer Excaliber hockey skates\u201d you would not only get an advertisement from the retailer but also if it\u2019s schema.org\/InStock at a location and distance to that store. It\u2019s a powerful conversion opportunity, exploiting the retailer\u2019s vast network of store and inventory, consumers get actionable information to go pick it up physically.\nLocal Inventory Ads Example\nPart of the conditions to LIA program is to have Schema.org data on Product detail pages at a level that details the availability in each store. For each schema.org\/Product and its schema.org\/ProductModel, we need to expose their schema.org\/Offer and its schema.org\/availableAtOrFrom StoreID.\nApproaches considered\nLike many large businesses, the Marketing team has numerous initiatives dependent on IT for delivery. They had an aggressive timeline, 8-10 weeks, when started we provided them several schema.org at scale options to consider. To maximize the number of data consumers of schema.org data we wanted to render the schema.org data server side, so that it is available in the HTML Document Object Model on page load.\n\nCustom Programming: Typically this meant encoding data into the Product Detail Page template, using either Microdata or JSON-LD This approach, however, relies heavily on the IT team which couldn\u2019t meet the aggressive schedule due to other commitments.\nBulk Data Transformation: Our next best option was to implement a bulk data transformation, which would take the same Google AdWords Feed and supplement with BazaarVoice review data.\nJavascript Rendering: The third approach is to implement Javascript which builds the JSON-LD dynamically after page load.\n\nUltimately, we chose #3 Javascript Rending because it involved no IT, it could meet the LIA requirements for Google in a short time and the data\/code remained within the control of the Business.\nProblems with SDTT & GTM Datalayer\nThe initial implementation by the team was to provide schema.org data mapped from Google Tag Manager Datalayer variables. The data layer had Product Information, Offers for different skus for the selected store and the BazaarVoice review data (AggregateRating). The only catch was, this data while convenient was only available after 5-10 seconds because of all the Javascript on the page to prepare the data. To add complexity, the retailer has different pricing for different stores. For example, Rural stores which incur more shipping costs could have higher prices than urban centers. Therefore, on each page load needs to first geolocate the user and suggest the closest store, before the prices could be shown. Similarly, BazaarVoices elements loads using Javascript and its data is loaded after a few seconds as well.\nWhen we tested the schema.org data, we found the <script type=\u201dapplication\/ld+json\u201d> when we inspected the HTML. However, when we tested with Google\u2019s Structured Data Testing Tool, the tool which does a good job processing Javascript, simply cut off the page after several seconds of Javascript processing and wouldn\u2019t show the data.\nThe Additive Experiment method\nWe set up a workshop to go through step-by-step, testing the limits of what could be done. The relevant Product information was spread throughout the webpage, so we wanted to explore the extent of what was possible. In order for this to be successful, we relied heavily on the Google\u2019s ability to reconcile JSON-LD data by its @id values. For example, given the two sample JSON-LD inputs below:\n{\n \"@context\": \"http:\/\/schema.org\/\",\n \"@type\u201d: \"Product\",\n \"@id\": \"#product\",\n \"name\": \"Blue Widget\"\n}\n\n{\n \"@context\": \"http:\/\/schema.org\/\",\n \"@type\": \"Product\",\n \"@id\": \"#product\",\n \"image\": \"http:\/\/cdn.amazon.com\/TheEnterprise\/product_blue_widget.jpeg\"\n}\nWould be reconciled by Google as:\n{\n \"@context\": \"http:\/\/schema.org\/\",\n  \"@type\": \"Product\",\n \"@id\": \"#product\",\n \"name\":\"Blue Widget\",\n \"image\": \"http:\/\/cdn.amazon.com\/TheEnterprise\/product_blue_widget.jpeg\"\n}\nTherefore, we would deconstruct the data into logical parts, then the additive data elements available to SDTT at the time it cuts off would show the problematic data by whats not shown. The first element, Basic Product Data that\u2019s available in the HTML DOM that comes from the server before any Javascript. When viewing a webpage, if you right-click and View Page Source, that HTML is what comes from the server. This is data which is immediately available to Javascript for parsing and could be published immediately. There, we found Product Name, one image in the meta og:image, the Product Description. We coded some Javascript selectors, e.g. document.querySelector, to build out a basic Product schema JSON-LD data block. As an example, to get the Product Image URL:\ndocument.querySelector('meta[property=\"og:image\"]') \nWe implemented this as a GTM Tag that triggers on DOM Ready and Published, ready for our first live test.\nTesting & Validation\nWhen testing on Google we found the data was being discovered.\n{\n \"@context\": \"http:\/\/schema.org\/\",\n \"@type\": \"Product\",\n \"@id\": \"#product\",\n \"name\": \"Blue Widget\",\n \"description\": \"Lots of great features!\",\n \"image\": \"http:\/\/cdn.amazon.com\/TheEnterprise\/product_blue_widget.jpeg\"\n}\nWhile it was a good first test step, we were still missing necessary aspects, including Offers and Reviews. The next attempt we made was to retrieve Offers. We looked backward from the data layer, to see how it was populated. We discover a Custom Javascript Event that published the Offers once a Store was select. We setup the trigger and once we found the pricing and availability information we were able to add the Offer. We appended this JSON-LD data block by referring back to the #product defined earlier and use the additive information.\n{\n \"@context\": \"http:\/\/schema.org\/\",\n \"@type\" :\"Product\",\n \"@id\": \"#product\",\n \"offers\": {\n \"@type\": \"Offer\",\n \"price\": 45.00,\n \"priceCurrency\": \"USD\",\n \"availability\": \"InStock\"\n }\n}\nIf the store is selected, we could include the schema.org\/availableAtOrFrom: \u201cStoreID123\u201d. This StoreID has to match those in the Google Business Profile (GBP) account. These are unique identifiers the Retailer assigns to them and reused for LIA and in schema.org markup.\nThis Offer data works great for Product with no variants or when for Multi-variant Products whose ProductModel (sku) is selected. In scenarios in which a Product has multiple variants \/ skus, instead of Offer we would show AggregateOffer with a lowPrice.\nRich Snippet Using AggregateOffer\nWhen testing this data block, we were less certain that the data would be available in time for the Javascript rendering for the SDTT. In this test it was available and the data automatically merged into the earlier data block.\nNext, we wanted to get the BazaarVoice data for AggregateReting data. We found the Javascript code that loads BazaarVoice and looked for a way to hook into the function. Being that the BazaarVoice Javascript was included in the Page Load DOM, our GTM tag is loaded too late to mutate the Javascript function. We instead attached a Javascript onChange listener to the DIV Review element. When that changes, we would get the rating count and rating value data from DOM elements innerHTML. We could then emit a third JSON-LD data block and tie in with the earlier data using the same @id : \u201c#product\u201d\n{\n \"@context\": \"http:\/\/schema.org\/\",\n \"@type\": \"Product\",\n \"@id\": \"#product\",\n \"aggregateRating\": {\n \"@type\": \"AggregateRating\",\n \"ratingCount\": 12,\n \"ratingValue\": 4.6\n }\n}\nWhen we published the tags and ran it through Google, the data was available in time and Google rendered the compiled JSON-LD data blocks. The Testing Tool also showed us the Preview button and Product rich result. Had the Javascript had too many delays and didn\u2019t make the cutoff, we knew which was data source was the culprit. A decision would be made whether to include what was discoverable. The data that doesn\u2019t show, we would revisit the Javascript event model to discover alternative methods.\nSDTT != Search Console Report. In our experience, if you find schema data is shown in the Structured Data Testing Tool you will find it in the Search Console Structured Data report after 3-5 days (unless its a large site and the pages haven\u2019t yet been reindexed). The opposite, however, isn\u2019t always true. There have been times where we have not seen data in the SDTT but we do find the data in the Search Console. So, even if we\u2019re at wit\u2019s end trying to get the data to show in Search Console, I would leave the GTM Tag in place until we confirm the Search Console report.\nFuture Work\nI really like the additive capability of composing schema.org markup data block by data block. Sometimes all the information isn\u2019t available at runtime and to meet the needs of an early adopter you need to experiment to make it work. In the future, our work with the client will involve adding How-To Videos, cross-sell products, upsell products, related links, additional images all using the additive method.\nOf course, this is all great for the retailer, they now receive Google rich snippets and LIA in time for the holiday shopping season. For other schema.org consumers, however, we are less fortunate as they less often support handle Javascript rendering like Google does. For these other consumers we need to include the data from the Server as part of the HTML sent back to the client. This is a business decision, however, what is the additional cost of the IT project to implement weighed against the provable ROI of supporting other data consumers.\nIf you need a hand getting started with your structured data strategy, we\u2019ve helped customers such as SAP and Keen Footwear drive more quality search traffic to their websites. \nStart reaching your online business goals with structured data.Let\u2019s Talk\n ","description":"Schema App demonstrates the additive capability of composing\u00a0schema.org markup data block by data block to unlock Googles Local Inventory Advertising."},{"@context":"http:\/\/schema.org","@type":"Organization","address":{"@type":"PostalAddress","streetAddress":"201 - 412 Laird Road","postalCode":"N1G 3X7","addressRegion":"Ontario","addressLocality":"Guelph","addressCountry":"https:\/\/www.schemaapp.com\/#Country","name":"Schema App Address","@id":"https:\/\/www.schemaapp.com\/#PostalAddress"},"logo":{"@type":"ImageObject","width":"290","height":"93","url":"https:\/\/ezk8caoodod.exactdn.com\/wp-content\/uploads\/2020\/07\/SA_Logo_Main_Orange_w300-1.png?strip=all&lossy=1&ssl=1","@id":"https:\/\/ezk8caoodod.exactdn.com\/wp-content\/uploads\/2020\/07\/SA_Logo_Main_Orange_w300-1.png?strip=all&lossy=1&ssl=1"},"potentialAction":{"@type":"ScheduleAction","name":"Schedule a Demo","url":"https:\/\/www.schemaapp.com\/book-a-demo\/","@id":"https:\/\/www.schemaapp.com\/#ScheduleAction"},"image":{"@type":"ImageObject","width":"1350","height":"650","url":"https:\/\/ezk8caoodod.exactdn.com\/wp-content\/uploads\/2021\/04\/Schema-App-Featured-Image.png?strip=all&lossy=1&ssl=1","@id":"https:\/\/ezk8caoodod.exactdn.com\/wp-content\/uploads\/2021\/04\/Schema-App-Featured-Image.png?strip=all&lossy=1&ssl=1"},"description":"Schema App is an end-to-end Schema Markup solution that helps enterprise SEO teams develop a knowledge graph and drive search performance.","knowsAbout":["http:\/\/www.wikidata.org\/entity\/Q1891170","https:\/\/www.wikidata.org\/wiki\/Q6108942","https:\/\/www.wikidata.org\/wiki\/Q26813700","https:\/\/www.wikidata.org\/wiki\/Q180711","http:\/\/www.wikidata.org\/entity\/Q33002955"],"keywords":["Structured Data","Knowledge Graph","Rich Results","Semantic Search","Search Engine Optimization","Schema Markup","Semantic Technology"],"location":"http:\/\/www.wikidata.org\/entity\/Q504114","sameAs":["https:\/\/www.instagram.com\/lifeatschemaapp\/","https:\/\/www.linkedin.com\/company\/2480720\/","https:\/\/twitter.com\/schemaapptool","https:\/\/www.youtube.com\/channel\/UCqVBXnwZ3YNf2BVP1jXcp6Q"],"legalName":"Hunch Manifest Inc","name":"Schema App","telephone":"+18554448624","url":"https:\/\/www.schemaapp.com\/","email":"support@schemaapp.com","knowsLanguage":"http:\/\/www.wikidata.org\/entity\/Q1860","areaServed":"http:\/\/www.wikidata.org\/entity\/Q13780930","@id":"https:\/\/www.schemaapp.com\/#Organization"},{"@context":"http:\/\/schema.org","@type":"Thing","name":"Structured Data","sameAs":["kg:\/m\/05p2j70","http:\/\/www.wikidata.org\/entity\/Q26813700","https:\/\/en.wikipedia.org\/wiki\/Structured_data"],"description":"information with a formal data model","alternateName":"Schema Markup","@id":"https:\/\/www.schemaapp.com\/entity#Thing6"},{"@context":"http:\/\/schema.org","@type":"Thing","name":"JSON-LD","sameAs":["https:\/\/www.wikidata.org\/wiki\/Q6108942","kg:\/m\/0hzq_55","https:\/\/en.wikipedia.org\/wiki\/JSON-LD"],"description":"JSON-LD is a method of encoding linked data using JSON. One goal for JSON-LD was to require as little effort as possible from developers to transform their existing JSON to JSON-LD. JSON-LD allows data to be serialized in a way that is similar to traditional JSON.","@id":"https:\/\/www.schemaapp.com\/entity#Thing2"}],{"@context":"https:\/\/schema.org\/","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Schema Markup","item":"https:\/\/www.schemaapp.com\/schema-markup\/#breadcrumbitem"},{"@type":"ListItem","position":2,"name":"Additive Schema.org Data for Local Inventory Advertising","item":"https:\/\/www.schemaapp.com\/schema-markup\/additive-schema-org-data-local-inventory-advertising\/#breadcrumbitem"}]}]