Add Structured Data (JSON-LD) to HTML Items From Index Fields

When using a Coveo Machine Learning (Coveo ML) Smart Snippets model to extract questions and answers from a web page, we recommend that you use Google structured data in JSON-LD format within the <head> of the web page HTML for optimal results.

In addition to, or in the absence of JSON-LD, the model searches headers (<h> tags) in HTML items and uses the content that appears within these headers to extract snippets. See Optimize the Content for further information on how Coveo ML Smart Snippets models leverage HTML content to extract snippets.

However, when using support-case content to build a Smart Snippets model (e.g., content originating from a Salesforce or ServiceNow source), this content may not be properly configured to be optimally used by the model.

This article provides instructions on how to create an indexing pipeline extension (IPE) that allows you to identify the index fields containing the questions and answers you want the model to use, and convert this content to JSON-LD format, which will be added in the <head> of the HTML item.

content browser showing answers and questions fields

Basic Recipe

The following code sample shows the post-conversion IPE script that can be used to specify the index field containing the questions and answers you want the model to use:

from bs4 import BeautifulSoup
import json
def get_safe_meta(meta_data_name):
  meta_data_value = document.get_meta_data_value(meta_data_name)
  if meta_data_value:
      return ''.join(char for char in meta_data_value[-1] if ord(char) < 128)
      return ''
def create_question(name, text):
  return {
      "@type": "Question",
      "name": name,
      "acceptedAnswer": {
          "@type": "Answer",
          "text": text
def clean_answer(answer: str):
 answer = answer.replace('\t', '&nbsp;&nbsp;')
 answer = answer.replace('\n', '<br/>')
 answer = answer.replace('\u00a0', '&nbsp;')
 return answer
def parse_answer(answer: str):
 return answer
body_html_stream = document.get_data_stream('body_html')
question = get_safe_meta(QUESTION_FIELD)
answer = clean_answer(get_safe_meta(ANSWER_FIELD))
questions = []
questions.append(create_question(question, parse_answer(answer)))
faq_schema = json.dumps({"@context": " ", "@type": "FAQPage", "mainEntity": questions})
faq_script = BeautifulSoup("""<script type="application/ld+json">""" + faq_schema + """</script>""", 'html.parser')
body_html_soup = BeautifulSoup(, 'html.parser')
output_stream = document.DataStream('body_html')
document.add_meta_data({"HasHTMLVersion": True})

Where you replace:

  • <QUESTION_FIELD> with the field that contain the questions you want the model to use.

  • <ANSWER_FIELD> with the field that contain the answers you want the model to use.

  • Below YOUR CUSTOM PARSING CODE HERE, you can optionally add custom code to adapt the IPE to your use case.


    The field that contain the answers you want the model to use may contain information that you don’t want the snippet to display.

    When configuring your Smart Snippets model, you selected sfresolution as a field to be used by the model to extract content.

    The content of the sfresolution field is configured as follows in the source you selected when configuring the model:

    <!doctype html>
    <title>My Document Title</title>
           Request Access
           Submit a ticket
           Fill out the request
           After the ticket is submitted, check your inbox for a confirmation.
      <h2>Additional Information</h2>
        Additional information can be found on our support website.

    To always provide relevant snippets, you modify the above IPE to include custom code that will only scope elements appearing within the Procedure section of the item’s HTML, and use this information as the answer section of the JSON-LD generated by the IPE.


This section provides instructions on how to create the post-conversion IPE script and assign it to the desired sources.

Step 1: Create the Indexing Pipeline Extension (IPE) Script

extension configuration
  1. On the Extensions page of the Coveo Administration Console, click Add extension.

  2. On the Add an Extension page, in the Extension name input, enter a meaningful name for your extension.

  3. In the Extension input, you can optionally add a description for your extension.

  4. In the Select additional item data that the extension needs to access section, select the Body HTML option.

  5. In the Select restricted parameters that the extension needs to access section, make sure the Vault parameters option is cleared.

  6. In the Extension script section, paste the IPE script and update the code to your needs.

  7. Assign the IPE script to your source.

Step 2: Assign the Indexing Pipeline Extension (IPE) Script to a Source

extension configuration
  1. On the Sources page of the Coveo Administration Console, click the source to which you want to apply the IPE, and then click More > Manage extensions in the Action bar.

  2. On the page that opens, click Add, and then select Extension.

  3. On the page that opens, in the Extensions section, select the IPE you created.

  4. In the Stage section, select Post-Conversion.

  5. In the Action on Error section, select Skip Extension.

  6. In the Apply to section, depending on whether your Coveo ML Smart Snippets model applies to specific item types:

    • If your Coveo ML Smart Snippets model doesn’t scope specific item types, select All items (common).

    • If your Coveo ML Smart Snippets model scopes specific item types, select Specific item types, and then specify the item types to which the IPE should apply.

  7. (Optional) In the Condition(s) to apply section, you can add a condition to the extension to scope the items on which the extension should apply (e.g., %[documenttype] == "Solution").

  8. Click Apply extension.

  9. Click Save and rebuild source to apply the IPE to your source.

To see the impact of the IPE in snippets extracted by a Coveo ML Smart Snippets model, you must update the model after the targeted sources have been rebuilt with the IPE.

What's Next for Me?