Documentation

Integration manual

Introduction

To use Luigi's Box tools you need to start tracking your search. We provide a tracker script which can read structured data about search and search results from standard schema.org annotations (we support both inline annotations or embedded json+ld). These annotations are not tied to your design and therefore robust against redesign and other frontend changes.

Luigi’s Box recognizes search and product microdata annotations in schema.org format - a standard and accepted way to give structure to data and make it understandable to machines.

You want to use schema.org annotations, because:

  • Google, Bing, Yahoo and other search engines use them to show rich snippets about your product directly on the search results page. Compare the following results and see how the first one with metadata stands out. Using schema.org is an amazing way to draw attention to your listing and stand out from the competition.
  • Apple’s Siri and Google’s Assistant can use them to answer questions about shopping. “Hey Siri, where can I buy a new phone?”
Search results

There are 2 ways to add schema.org annotations to your web, and both are supported by Luigi's Box:

  • Using an inline markup and adding additional HTML attributes where appropriate.
  • Embedding a separate JSON object which includes all semantic information in one place.

Both options are equivalent, as they convey the same semantic information. They only differ in the used notation. When you choose inline markup, you have to interspere the annotations throughout the HTML, but on the other hand, there is no duplicated information. When you use a JSON object, the semantic data is contained in a single place, but duplicates the information that is already present in HTML.

Based on our experience, inline annotations are easier to maintain, but the embedded JSON document is somewhat easier to implement and understand, especially when you are adding schema.org annotations for the first time.

Concepts

Regardless of which implementation you choose (inline annotations or JSON+LD), there are several concepts that you need to know about and which, together, form a complete information about the search performed.

  • query — what the user typed into your searchbox
  • filters — additional restrictions used, e.g. search only in "Accessories" department
  • search results — specifically title, URL address, position in the list of results and price (if applicable).
  • conversion intent — did the user add an item to the shopping cart?

Query

Query is what the user typed into the search box to get search results. It is important that you don't encode the query in any way (e.g., you should do no percent-encoding, or whitespace trimming). Use excactly the same query string that the user typed, even if you do some internal preprocessing before using the query for search.

Note, that a valid search may not have a query at all. E.g., image a scenario when using an advanced search and the user types no query, but chooses to search for all products in stock. In this case you would use empty query with filters. See below for filters explanation.

Filters

Anything that influences which products are displayed should be annotated as filters. Sorting, or facets, or sometimes even the category have effect on what is displayed.

Luigi's Box only cares about active filters. When you are showing a facet where a user can limit phones by the manufacturer, but the user did not select anything yet, it's not a filter and you should not send it.

Filters

Take a look at the picture above. There are 4 filters: Color, Price, Brand and Sort by. Notice that the Brand filter is unused so there is no need to annotate it. In this case, you should send: Color: Black, Price: 20-800, Sort: Price.

Not that some filters are implicit and not visible or modifiable by the user. Imagine a scenario where your users are assigned specific access levels and you are limiting the search results to only show results the user can access. In this case, you should send the access level as a filter.

Search results

The relevant information about search result is:

  • Title — this will usually be the same title as you are showing to the user, e.g. a product title. The title is not required to be unique (and in many cases won't, but that's ok).
  • URL — the canonical link to the search result (e.g. a product). It should be valid URL, including http/https protocol. The URLs should be unique, and each URL should link to exactly one product. In our experience, the most common problem that we see is that the URLs are not canonical. The URL should only contain enough parameters that it still links to the product and nothing more. Some examples of URLs that violate this requirement are:
    • https://www.example.com/products/black-shirt?ref=search
      — notice the ref parameter which is not necessary for the link to work and is only used for analytical purposes.
    • https://www.example.com/products/black-shirt?q=shirt&page=2
      — notice the q and page parameters which are not necessary for the link to work and are only used to construct a link back to search.
    • https://www.example.com/products/black-shirt?gclid=283h1bxz81jzgj
      — notice the gclid parameter which is not necessary for the link to work and is only used for tracking purposes.
    In all cases, the canonical URL should be
    https://www.example.com/products/black-shirt
  • Position — a number indicating a search result position in the full list of search results, considering pagination.
  • Price — (optional) price of the product. This may not be always available, e.g., the product is not in stock anymore, or the search result is a blog post, which is not sellable and thus has no price. It's ok to not annotate any price.

Luigi's Box only cares about search results that are visible. Imagine a scenario where your search found thousands of search results, but you only present a list of first 20 search results, along with a pagination component, which lets the user scroll through the search results and view additional results.

In this case, you should only annotate the 20 visible search results, and ignore the rest. The first results will have position 1, the last position 20. When the user clicks through to page 2, annotate the visible results, and the first result will have position 21, the last one position 40.

Conversions

Everything that is important to you from the business perspective can be tracked as “conversion”, regardless whether it is an action of “buying” an item, “liking” it, “favoriting” it, or anything else.

There are usually many different types of conversions found at different places.

  • It is usually possible to convert both from the list of search results and the product detail itself. You should annotate both conversion actions.
  • It's ok to have several conversion actions for the same product, e.g. buy a product, or add a product to favorite list. Just make sure to give each conversion a different name.

Autocomplete

The process of annotating autocomplete results is the same as with the regular Search Results. Here are the notable differences:

  • Autocomplete is usually not paginated, so you can safely skip the position annotations.
  • In case your Autocomplete results don't show prices, you can safely skip the price attribute.
  • Sometimes autocomplete can have filters too. See the image below for a an example. In this case, you must annotate this filter, e.g. Category: Phones.
Searchbox

Product listings

Any display of product list which is of interest can be considered a “search”. Therefore, if the user clicks a menu element and is taken to the list of products which he/she can manipulate through filters and/or sort, this is considered a “search” too (albeit without a query, only with filters, if any) and you should send it to Luigi's Box to be analyzed. It makes sense to send the category name as a filter.

Embedded JSON+LD

This section talks about implementation details, before you dive in make sure to read the concepts part which will help you understand what to track and why.

While you are developing the integration, we recommend that you turn on data linter to see debugging information. See Troubleshooting section for more details.

A basic example

The sample document below shows all concepts in a JSON+LD format. You should include a document similar to this, wrapped in a script tag somewhere in your page HTML code. Click the hints on the right to learn more.

Sample JSON+LD document
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "SearchAction",
  "query": "phone",
  "result": {
    "@type": "ItemList",
    "name": "Search Results",
    "itemListElement": [
      {
        "@type": ["ListItem", "Product"],
        "position": "1",
        "name": "Android Phone PX100",
        "url": "https://myshop.com/products/236",
        "offers": {
          "@type": "Offer",
          "priceCurrency": "EUR",
          "price": "120"
        }
      },
      {
        "@type": ["ListItem", "Product"],
        "position": "2",
        "name": "iPhone X",
        "url": "https://myshop.com/products/293",
        "offers": {
          "@type": "Offer",
          "priceCurrency": "EUR",
          "price": "999"
        }
      }
    ]
  },
  "instrument": [{
    "@type": "ChooseAction",
    "name": "Sort by",
    "actionOption": "Relevance"
  },
  {
    "@type": "ChooseAction",
    "name": "Color",
    "actionOption": ["Black", "Silver"]
  }]
}
</script>
Hints
The JSON+LD document must be embedded inside a script tag with type="application/ld+json"
The special @context attributes marks this as schema.org-compatible
The special @type attributes marks this as search-related information in the shema.org vocabulary
The query that the user entered.
This field is called result in schema.org, which is a bit confusing since it will contain an array of results.
The list name. Valid values here are "Search Results" for regular search results andAutocomplete" for autocomplete results.
The instrument field contains an array of filters.
A special @type attribute marks this as filter in schema.org vocabulary.
This is the filter name.
When a single filter has multiple values, you can include all values at once in an array.

Conversions

Conversion actions cannot be embedded directly in the JSON+LD document, so you'll need to add HTML data-action attributes to conversion elements. Make sure that you are adding the annotation to all places where users can convert. This usually includes:

  • Search results list: Most sites include an "Add to cart" button next to each product directly in the list of search results. Add the data-action attribute to all buttons on the search results page.
  • Product detail: Add the data-action annotation to appropriate buttons on the product detail page. This will usually be an "Add to cart" button.

It is acceptable to use several different conversion types. Most common conversion types in e-commerce are "buy" and "wishlist". Choose whatever names are convenient for you, you will be able to filter and segment on conversion type in Luigi's Box Search Analytics.

In some cases, you may want to send a negative conversion (i.e. user clicks a thumbs-down button). We use negative conversions as additional signal when learning optimal search ranking.

Conversion
<div data-action="buy">
    Add to cart
</div>
<div data-action="wishlist">
    Add to wishlist
</div>
<div data-action="thumbs-down" data-action-attitude="negative">
    Thumbs down
</div>
Hints
The data-action="buy" code will consider clicks anywhere within the element as conversion action with type "buy".
The data-action="wishlist" code will consider clicks anywhere within the element as conversion action with type "wishlist".
The data-action-attitude="negative" will consider clicks anywhere within the element as a negative conversion actions.

Autocomplete

When you update Autocomplete results, you should also update the JSON+LD document for the Autocomplete search. A good strategy is to assign the script tag containing the Autocomplete JSON+LD a special id attribute and then replace its contents with new JSON+LD.

Sample JSON+LD document for Autocomplete
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "SearchAction",
  "query": "phone",
  "result": {
    "@type": "ItemList",
    "name": "Autocomplete",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": "1",
        "name": "Android Phone PX100",
        "url": "https://myshop.com/products/236",
      },
      {
        "@type": "ListItem",
        "position": "2",
        "name": "iPhone X",
        "url": "https://myshop.com/products/293",
      }
    ]
  }
}
</script>
Hints
It is important that the name attribute is set to "Autocomplete" to mark this as an autocomplete list.

No search results

When your search returns no results, you need to add a json+ld markup anyway. You must annotate the query, the used filters and the search name (Search Results/Autocomplete). Since your search returned no results, set itemListElement to empty array.

JSON+LD for no search results
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "SearchAction",
  "query": "skirt",
  "result": {
    "@type": "ItemList",
    "name": "Search Results",
    "itemListElement": []
  },
  "instrument": [{
    "@type": "ChooseAction",
    "name": "Color",
    "actionOption": "Black"
  }]
}
</script>
Hints
Notice that "itemListElement" attribute is present, but set to empty array since there are no results.

Infinite scrolling

When your site is using infinite scrolling, you should update the JSON+LD document for regular search results. It is not necessary to build JSON+LD document for all visible search results — only build the JSON+LD for the search results that were freshly loaded.

Inline schema.org annotations

This section talks about implementation details, before you dive in make sure to read the concepts part which will help you understand what to track and why.

While you are developing the integration, we recommend that you turn on data linter to see debugging information. See Troubleshooting section for more details.

A basic example

A HTML representation of a product like the one below..
Simple product
<div id="product-6">
    <a href="/products/6?ref=search" class="prod-name">Milk</a>
    <span class="prod-price">25</div>
</div>

..can be made readable by software by adding just a few simple annotations telling what it describes — a list of search results showing single product with a price:

Machine-readable search results
<div itemscope itemtype="http://schema.org/SearchAction">
    <meta itemprop="query" content="phone">
    <div itemprop="result" itemscope itemtype="http://schema.org/ItemList">
      <meta itemprop="name" content="Search Results">
      <div id="product-6" itemprop="itemListElement" itemscope
    itemtype="http://schema.org/Product http://schema.org/ListItem">
        <a href="/products/6?ref=search" class="prod-name" itemprop="name">Milk</a>
        <meta itemprop="url" content="http://example.com/products/226">
        <div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
            <span class="prod-price" itemprop="price">25</div>
            <meta itemprop="priceCurrency" content="EUR">
        </div>
      </div>
    </div>
    <div style="display:none !important;" itemprop="instrument"
     itemscope itemtype="http://schema.org/ChooseAction">
        <meta itemprop="name" content="Color">
        <meta itemprop="actionOption" content="Black">
    </div>
  </div>

The example above shows all the basics and encodes information about query, filters and search results. Please see the further sections for more details.

Using annotations - the itemscope, itemtype and itemprop HTML attributes, you can add deeper meaning and structure to the data. When using the schema.org annotations, keep in mind these rules:

  • You create new scopes (contexts) by using itemscope & itemtype attributes. These attributes convey that the element describes an item of a type (e.g, a Product) and its descendant nodes describe its properties.
  • itemprop – You tell that this element contains a property of the parent item. This can be a “text content” of a user visible element (price in the example), or it can be defined using an invisible meta element (currency in the example).
  • Make sure that you adhere to the nesting rules. The top-level itemscope must be http://schema.org/SearchAction. The nesting must be like this:
    > SearchAction
        - itemprop="query"
        > itemprop="result", ItemList
            - itemprop="name"
            > itemprop="itemListElement", ListItem
                - itemprop="name"
                - itemprop="url"
                - itemprop="position"
                > itemprop="offers", Offer
                    - itemprop="price"
            > itemprop="itemListElement", ListItem
              ...
        > itemprop="instrument", ChooseAction
            - itemprop="name"
            - itemprop="actionOption"
        > itemprop="instrument", ChooseAction
            ...
  • itemprop values are extracted either from textContent of the element, e.g. here
    <span itemprop="name">Milk</span>
    Milk will be used as "name" attribute. Or you can use "content" attribute to overide textContent, e.g.
    <span itemprop="name" content="Cheese">Milk</span>
    Cheese will be used as "name" attribute.
  • Visibility is not taken into account when parsing the data. The attributes must not be user-visible and can be safely hidden with CSS. You can also use a <meta> tag which is invisible by default. Just keep in mind that the meta tag must be open and has no textContent so you must use an explicit "content" attribute.

Query

Schema.org annotations require strict nesting. The markup that defines search must be placed somewhere on top of the page so the results can be nested inside.

Find a suitable HTML element which includes the list of results and place the following markup.

Query
<body>
    <nav>…</nav>
    <section class="container-fluid">
        <input type="text" name="q" value="phone"/>
        <div itemscope itemtype="http://schema.org/SearchAction">
            <meta itemprop="query" content="phone">
            <div itemprop="result" itemscope itemtype="http://schema.org/ItemList">
                …
            </div>
    </section>
</body>
Hints
SearchAction is a base schema.org entity encapsulating search. Everything related to search - query, results and filters must be nested under this entity.
We are showing the query back to the user in the text input field. It is repeated here just for the purpose of annotation. There's no need to show the query twice — we used an invisible meta tag.
Results should be nested somewhere inside the SearchAction.

If your site has autocomplete, make sure that the autocomplete results/suggestions are not nested under the same SearchAction as the regular search. It's usually not a problem, since most of the autocomplete libraries place the HTML markup for autocomplete results at the bottom of the HTML, just before the closing body tag.

Results

Results
<div … itemprop="result" itemscope itemtype="http://schema.org/ItemList">
    <meta itemprop="name" content="Search Results">
    <a href="/products/236" … itemprop="itemListElement"
   itemscope itemtype="http://schema.org/Product http://schema.org/ListItem">
        <meta itemprop="position" content="1">
        <div itemprop="name">Android Phone PX100</div>
        <meta itemprop="url" content="https://myshop.com/products/236">
        <div style="display:none !important;"
     itemprop="offers" itemscope itemtype="http://schema.org/Offer">
            <meta itemprop="priceCurrency" content="EUR">
            <meta itemprop="price" content="120.00">
        </div>
    </a>
    <a href="/products/237" … itemprop="itemListElement" itemscope
   itemtype="http://schema.org/Product http://schema.org/ListItem">
        <meta itemprop="position" content="2">
        …
    </a>
    <a href="/products/123" … itemprop="itemListElement" itemscope
   itemtype="http://schema.org/Product http://schema.org/ListItem">
        <meta itemprop="position" content="3">
        …
    </a>
  </div>
Hints
This indicates a list of results. Notice that there are actually two things happening at once. We are annotating a result itemprop of the parent SearchAction and at the same time declare that the results are an ItemList entity.
A name for the list of search results. For search analytics purposes, this needs to be set to "Search Results".
This indicates an item in the list of search results — a search result. Each result has two schema.org types. It is a Product but also a ListItem at the same time.
Invisible element with the result position. When you use pagination, this should be the position in the paginated list, e.g., assuming pages of 10 items, the first item on a 2nd page should be 11.
Product name - this is what you'll see in Luigi's Box dashboards.
Use canonical product URL here. Do not include tracking parameters, query, or other parameters that have no effect on which product is displayed. It's ok to use those parameters on the user clickable URL though, just don't use them here.
schema.org requires that the price is nested inside Offer itemtype.
Make sure that the price parses as a floating point number. That means using dot (.) instead of comma (,) to separate the fractional part of the price. E.g., "24,3" is wrong and "24.3" is correct. Also using currency symbols here is invalid, the currency is already specified.

Make sure that in the HTML structure, the ItemList is nested under SearchAction!

Sometimes the user can switch view type from list to grid. Make sure that items in all views are annotated.

Filters

Filters can get complicated very fast. When you use facets, price range selectors, sorting etc., there can be many filters each with a different HTML structure. You could annotate the filters in-place, but there is a much easier way. Put the markup for all active filters in a single place, inside invisible elements, somewhere inside the SearchAction.

Filters
<div style="display:none !important;" itemprop="instrument"
     itemscope itemtype="http://schema.org/ChooseAction">
    <meta itemprop="name" content="Color">
    <meta itemprop="actionOption" content="Black">
</div>
<div style="display:none !important;" itemprop="instrument"
     itemscope itemtype="http://schema.org/ChooseAction">
    <meta itemprop="name" content="Price">
    <meta itemprop="actionOption" content="20-800">
</div>
<div style="display:none !important;" itemprop="instrument"
     itemscope itemtype="http://schema.org/ChooseAction">
    <meta itemprop="name" content="Sort">
    <meta itemprop="actionOption" content="Price">
</div>
Hints
Each filter is an instrument of the SearchAction.
Each filter is a nested schema.org entity — a ChooseAction.
The name itemprop relates to the ChooseAction scope and is a name of the filter. The value can be arbitrary, whatever you use, we'll show you in Luigi's Box analytics verbatim, so it's best to use a name that will make sense to you later.
The actionOption is a filter value. Again, the value is arbitrary, but it's best to use the exact same value that the user sees.
Here we have declared a filter called 'Sort'. The name is arbitrary, but notice that even a sort is a filter. Anything that has influence on which items you show is a filter.

When you have a multi-value filter, e.g., a facet with checkboxes, just repeat the actionOption meta tag.

Multi-value filters
<div style="display:none !important;" itemprop="instrument"
     itemscope itemtype="http://schema.org/ChooseAction">
    <meta itemprop="name" content="Brand">
    <meta itemprop="actionOption" content="Samsung">
    <meta itemprop="actionOption" content="Lenovo">
    <meta itemprop="actionOption" content="Apple">
</div>
Hints
It's ok to repeat actionOptions, but it's not ok to have multiple ChooseAction-s with the same name.

Make sure that in the HTML structure, the ChooseActions are nested under SearchAction!

Autocomplete

The process of annotating autocomplete results is the same as with the regular Search Results. You must create a separate SearchAction that cannot be nested inside the SearchAction for regular Search Results.

Autocomplete
<div …  itemscope itemtype="http://schema.org/SearchAction">
  <div itemprop="query">phone</div> 
  <div itemprop="instrument" itemscope itemtype="http://schema.org/ChooseAction">
      <meta itemprop="name" content="category">
      <meta itemprop="actionOption" content="Phones">
  </div> 
  <div … itemprop="result" itemscope itemtype="http://schema.org/ItemList">
      <meta itemprop="name" content="Autocomplete">

      <a href="/products/236" … itemprop="itemListElement" itemscope
   itemtype="http://schema.org/Product http://schema.org/ListItem">
      <meta itemprop="position" content="1">
      <div itemprop="name">Android Phone PX100</div>
      <meta itemprop="url" content="https://myshop.com/products/236">
      <div style="display:none !important;" itemprop="offers" itemscope  
     itemtype="http://schema.org/Offer">
        <meta itemprop="priceCurrency" content="EUR">
        <meta itemprop="price" content="120.00">
      </div>
    </a>

    <a href="/products/237" … itemprop="itemListElement" itemscope
   itemtype="http://schema.org/Product http://schema.org/ListItem">
        …
    </a>
    <a href="/products/123" … itemprop="itemListElement" itemscope
   itemtype="http://schema.org/Product http://schema.org/ListItem">
        …
    </a>
  </div>
</div>
Hints
Autocomplete annotations must be nested under their own SearchAction.
On the rare occasion that your autocomplete uses filters, include them here. See the image above for an example of autocomplete with filters.
In the image above, you can see that the filter has no visible name, but we name it 'category'.
The ItemList must be named Autocomplete.
Autocomplete items are usually not paginated, so the explicit item position is not necessary.
If your autocomplete items show prices, feel free to anotate them, they are not required in this context though.

No results

When your search returns no results, you need to add schema.org annotations anyway. You must annotate the query, the used filters and the search name (Search Results/Autocomplete). Since your search returned no results, do not include any ListItems.

No results
<div itemscope itemtype="http://schema.org/SearchAction">
  <div itemprop="query">phone</div> 
  <div itemprop="instrument" itemscope itemtype="http://schema.org/ChooseAction">
      <meta itemprop="name" content="category">
      <meta itemprop="actionOption" content="Phones">
  </div> 
  <div itemprop="result" itemscope itemtype="http://schema.org/ItemList">
      <meta itemprop="name" content="Search Results">
      <span>No results found!</span>
  </div>
</div>

Conversions

Use a FindAction from schema.org to annotate conversion elements. Any element where click should be tracked can be annotated in the following manner, either in search results or on individual product pages:

Conversions
<button type="submit" itemscope itemtype="http://schema.org/FindAction">
    <meta itemprop="name" content="buy">
    <span …>
        Add to cart
    </span>
</button>
Hints
Each conversion must be nested under a FindAction. Think about it as an action you can do when you have found what you have been looking for.
Name of the action can be replaced with any text of choice, e.g. "favorite", "wishlist".

There are usually many different types of conversions found at different places.

  • Search results list: Most sites include an "Add to cart" button next to each product directly in the list of search results. Add the FindAction annotations to all buttons on the search results page.
  • Product detail: Add the FindAction annotation to appropriate buttons on the product detail page. This will usually be an "Add to cart" button.

It is acceptable to use several different conversion types. Most common conversion types in e-commerce are "buy" and "wishlist". Choose whatever names are convenient for you, you will be able to filter and segment on conversion type in Luigi's Box Search Analytics.

In some cases, you may want to send a negative conversion (i.e. user clicks a thumbs-down button). We use negative conversions as additional signal when learning optimal search ranking.

Conversions
<button type="submit" itemscope itemtype="http://schema.org/FindAction">
    <meta itemprop="name" content="thumbs-down">
    <meta itemprop="additionalType" content="http://schema.org/DislikeAction">
    <span …>
        Add to cart
    </span>
</button>
Hints
You can choose any conversion name that you like.
To mark the conversion as negative, set additionalType to DislikeAction.

Individual products

Although our collector framework does not need to know about individual products on their product pages apart from the annotations of the converting actions (buy, etc.), since we derive all the attributes from search results we saw, it may be beneficial to also annotate product pages, since external search engines and other tools do use them. Refer to example in the intro. Further information can be found here: https://developers.google.com/search/docs/data-types/products.

Frequent problems

Here's a list of frequent problems that we have noticed with implementation.

  • Malformed JSON in JSON+LD integration. We've seen many cases of malformed JSON, but the most common error is a trailing comma at the end of the JSON array. If you suspect that your generated JSON+LD is not valid, open the browser developer tools (usually by pressing F12 key) and switch to the Console tab. If we cannot parse the JSON, we will show an error message.
  • Bad or no results list name. We collect and analyze only searches where the ItemList name is present and set to "Search Results" or "Autocomplete" (mind the capitalization). If you set the list name to something else we will ignore that list altogether.
  • No annotations for "no search results". When your search returns no results, the backend system very often renders a completely different HTML template which is missing the annotations. Please check the corresponding section for JSON+LD no search results or inline annotations no search results.
  • Are you setting product positions with respect to pagination? Result position should be relative to full search results list. When you are showing 10 results per page, then on 2nd page in pagition, the products should be numbered 11–20. On 3rd page 21–30. A very frequent problem that we are seeing is that the positions on each page in pagination start from 1 again.
  • Query string is encoded. Sometimes we see that the query is URL encoded (percent-encoding) and it leads to double encoding since we encode the query again if necessary. It's best to use the query as is and leave encoding to us.
  • No conversion annotations. Very often, clients implement search results tracking and then forget about conversion tracking. Please check the corresponding section for JSON+LD conversions or inline annotations conversions.
  • No conversion annotations on product detail. Make sure to implement conversion tracking on both search results page and product detail page. Please check the corresponding section for JSON+LD conversions or inline annotations conversions.
  • No filter annotations. Very often filter annotations are missing, but they are as important as the query string. Consider that your query "skirt" is returning results and converting very well, but as soon as users check "Color: black" in your facets, your search returns no results. Filter are a natural part of the query and you should track them. Please check the corresponding section for JSON+LD filters or inline annotations filters.

Troubleshooting

While you are developing the integration, we recommend that you turn on data linter to see debugging information. Make sure that Luigi's Box integration script is included in the page and then, in your web browser, open the developer console (usually by pressing the F12 key), find the "Console" tab and type in the following command

Luigis.lint = true

After that, reload the page, but do not close the developer console. Each time, the integration collects search-related data, you will see what was parsed from your site and you'll get a report about data quality in the console tab of the developer tools.

When running in linting mode, the data you send is not stored and analyzed. You won't see it in any of the reports in Luigi's Box application.

If you've done everything correctly, you should see a blue Luigi's Box logo. If there were some problems with the data, you will see a red logo and a list of errors.

If you are not seeing the linter messages and logos, the most probable cause is that you are already running an early version of integration that does not support linting. Let us know and we will upgrade your integration.

Left side: no errors found.  Right side: linter found some errors.

Support

Troubles? Different nesting? Cannot get it to work? Contact us at support@luigisbox.com, we are glad to help!