--- title: Index Contentful content slug: o9ue0387 canonical_url: https://docs.coveo.com/en/o9ue0387/ collection: coveo-for-contentful source_format: adoc --- # Index Contentful content This article explains how to create and configure a generic Coveo GraphQL API source to use the Contentful GraphQL Content API endpoint, and optimize your indexing strategy. This approach ensures that you collect and effectively use your content for enhanced search experiences. The examples provided show how to configure the source to index `Article` items, where each article will be a document in the Coveo index available for search and recommendations. ## Create a GraphQL API source Follow the instructions below to add a GraphQL API source that uses the Cloud [content retrieval method](https://docs.coveo.com/en/1612/). . On the [**Sources**](https://platform.cloud.coveo.com/admin/#/orgid/content/sources/) ([platform-ca](https://platform-ca.cloud.coveo.com/admin/#/orgid/content/sources/) | [platform-eu](https://platform-eu.cloud.coveo.com/admin/#/orgid/content/sources/) | [platform-au](https://platform-au.cloud.coveo.com/admin/#/orgid/content/sources/)) page, click **Add source**. . In the **Add a source of content** panel, select the **Cloud** (icon:cloud-icon[alt=cloud-icon,width=16]) tab. . Click the **GraphQL API** tile. . [Configure your source](#configure-your-source). ## Configure your source When creating a GraphQL API source in the Coveo Administration Console, you must provide a JSON configuration that specifies which content to crawl and how to retrieve each type of item. ![GraphQL API Source JSON configuration example | Coveo Platform](coveo-for-contentful/contentful-graphql-json-config.png) ### "Authentication" section To establish a proper connection to the GraphQL Content API, enter your API key and other necessary authentication details in the **Authentication** section of the GraphQL source configuration panel. For more information about the API Key, refer to [Contentful API Key](https://www.contentful.com/developers/docs/references/authentication/). ### "Content to include" section In the JSON configuration box, add the configuration that defines the call to perform against the Contentful GraphQL Content API endpoint and how Coveo will handle the response. See [JSON configuration reference](#json-configuration-reference) for details. The following example show how to configure the source to index the item `Article`, where each article will be a document in the Coveo index available for search and recommendations. The configuration has a single property, Services, whose value must be an array of objects. **Example** ```json { "Services": [ { "Url": "https://graphql.contentful.com", "Headers": { "Authorization": "Bearer @ApiKey" }, "Endpoints": [ { "paging": { "offsetType": "item", "pageSize": 25, "TotalCountKey": "data.barcaHelpCollection.total" }, "Path": "content/v1/spaces/", "Method": "GET", "ItemPath": "data.barcaHelpCollection.items", "SkippableErrorCodes": "404", "ItemType": "Article", "Body": "%[body]", "Uri": "https://help.barca.group/article/%[cat_slug]", "ClickableUri": "https://help.barca.group/article/%[cat_slug]", "Title": "%[title]", "ModifiedDate": "%[sys.publishedAt]", "Metadata": { "articletags": "%[tags[*]]", "cat_slug": "%[slug]", "ec_category": "%[ecCategory[*]]", "ec_description": "%[ecShortdesc]", "ec_shortdesc": "%[ecShortdesc]", "eng_blogimage": "%[engBlogimage.url]", "objecttype": "Article", "thumbnailurl": "%[engBlogimage.url]?w=240" }, "PayloadJsonContent": "@query" } ] } ] } ``` ### "GraphQL queries" section Configure the desired GraphQL query to define the items and fields. Each item in the query will be a document in the Coveo index that will be part of search or recommendations. Each Coveo field will either be populated with the body of the document or a returned piece of [metadata that you have mapped](https://docs.coveo.com/en/o3ca0547#step-2-create-a-source-mapping-and-a-field). . Click **Add query**. . Name your query (for example, `@query`). The **GraphQL query** field will reference your query by its name. . In the **GraphQL query** field, enter your query. > **Tip** > > Use the [GraphiQL App](https://www.contentful.com/marketplace/graphiql/) to define your GraphQL query. Consider the following GraphiQL App screenshot showing a sample query and the returned results: ![Example query in Contentful GraphQL Explorer](coveo-for-contentful/contentful-graphql-explorer.png) ```text query Query { barcaHelpCollection (skip:@offset, limit:@pageSize) { total items { body { json } ecCategory ecShortdesc objecttype slug tags title engBlogimage { url } sys { publishedAt } } } } ``` Each document indexed by Coveo must have a unique URL. This is why the value of the `Uri` parameter (that is, `+https://help.barca.group/article/%[cat_slug]+`) in the [sample JSON configuration](#content-to-include-section) is populated by concatenating: * a static value (that is, `+https://help.barca.group/article/+`), and * the extracted `cat_slug` dynamic metadata value (that is, `%[cat_slug]`). > **Notes** > > * If the URL returned in the Query field doesn't return the desired properties, consider adding an [indexing pipeline extension (IPE)](https://docs.coveo.com/en/3394/) or using the [Sitemap source](https://docs.coveo.com/en/1967/) instead. > > * Include `_modified` or changed fields in your query to ensure that your [scheduled content updates](https://docs.coveo.com/en/1933/) pick up changes in a timely manner and that your indexed content remains fresh. ## JSON configuration reference ### ["Services"](https://docs.coveo.com/en/o1ae7549#services-array-required) object ```json "Services": [ { "Url": "https://graphql.contentful.com", "Headers": { "Authorization": "Bearer @ApiKey" }, "Endpoints": [ { "paging": { "offsetType": "item", "pageSize": 25, "TotalCountKey": "data.barcaHelpCollection.total" }, "Path": "content/v1/spaces/", "Method": "GET", "ItemPath": "data.barcaHelpCollection.items", "SkippableErrorCodes": "404", "ItemType": "Article", "Body": "%[body]", "Uri": "https://help.barca.group/article/%[cat_slug]", "ClickableUri": "https://help.barca.group/article/%[cat_slug]", "Title": "%[title]", "ModifiedDate": "%[sys.publishedAt]", "Metadata": { "articletags": "%[tags[*]]", "cat_slug": "%[slug]", "ec_category": "%[ecCategory[*]]", "ec_description": "%[ecShortdesc]", "ec_shortdesc": "%[ecShortdesc]", "eng_blogimage": "%[engBlogimage.url]", "objecttype": "Article", "thumbnailurl": "%[engBlogimage.url]?w=240" }, "PayloadJsonContent": "@query" } ] } ] ``` ### ["Url"](https://docs.coveo.com/en/o1ae7549#url-string-required) object The `Url` value is the Contentful GraphQL query URL. The GraphQL API source configuration Url will be as follows: ```json "Url": "https://graphql.contentful.com" ``` ### ["Authentication"](https://docs.coveo.com/en/o1ae7549#authentication-object) object To establish a proper connection to the GraphQL Content API, enter your API key and other necessary authentication details in the **Authentication** section of the GraphQL source configuration panel. For more information about the API Key, refer to [Contentful API Key](https://www.contentful.com/developers/docs/references/authentication/). ![Edit GraphQL API Source configuration screen | Coveo](coveo-for-contentful/edit-graphql-api-sources.png) Use the `@ApiKey` placeholder to retrieve the value specified in the [GraphQL API source configuration panel](#authentication-section). ```json "Headers": { "Authorization": "Bearer @ApiKey" } ``` ### ["Endpoints"](https://docs.coveo.com/en/o1ae7549#endpoints-array-required) object ### ["Paging"](https://docs.coveo.com/en/o1ae7549#paging-object) object Pagination is a technique used in web development and APIs to divide a large dataset into smaller, more manageable chunks called pages. When configuring the GraphQL API source, pagination allows users to navigate through the data by requesting and displaying one page at a time. In the context of the GraphQL API source, pagination is being used to retrieve data from the API sequentially, where each request fetches one page of data. This approach helps optimize performance and reduce the amount of data transferred between the client and the server. When building the query, include the `total` field to indicate the total number of pages. This is calculated by the server-side GraphQL implementation to provide the total count of items matching the query's filters. In the source configuration, include the [`pageSize`](https://docs.coveo.com/en/o1ae7549/) to specify the number of items per page, the [`offsetType`](https://docs.coveo.com/en/o1ae7549/) to specify to Coveo how your API paginates its content, and the [`totalCountKey`](https://docs.coveo.com/en/o1ae7549#totalcountkey-string) that specifies the total expected number of items through the data object. Then, in your GraphQL query, include the tokens `@pageSize` and `@offset`. Coveo will replace `@pageSize` with the value of the `pageSize` parameter in your paging configuration. Similarly, `@offset` will be replaced with the value extracted from the response, depending on the paging method selected in [`offsetType`](https://docs.coveo.com/en/o1ae7549#offsettype-string-enum-required). ```json "paging": { "offsetType": "item", "pageSize": 25, "TotalCountKey": "data.barcaHelpCollection.total" } ``` ```text query Query { barcaHelpCollection (skip:@offset, limit:@pageSize) { ... } } ``` ### ["IndexingAction"](https://docs.coveo.com/en/o1ae7549#indexingaction-object) object This section determines whether to ignore or retrieve an item based on a condition. When the condition is true, the Coveo crawler applies the specified action to the item. Possible actions are `Retrieve` and `Ignore`, meaning the crawler can either index the item or ignore it. An item ignored with `IndexingAction` isn't indexed and therefore isn't visible in the [**Content Browser**](https://platform.cloud.coveo.com/admin/#/orgid/content/browser/) ([platform-ca](https://platform-ca.cloud.coveo.com/admin/#/orgid/content/browser/) | [platform-eu](https://platform-eu.cloud.coveo.com/admin/#/orgid/content/browser/) | [platform-au](https://platform-au.cloud.coveo.com/admin/#/orgid/content/browser/)) or a search interface. In the provided example, only items where `my_locale` equals `"en"` are indexed. ```json "IndexingAction": { "ActionOnItem": "Ignore", "Condition": "NOT(%[my_locale] == \"en\")" } ``` ### ["Path"](https://docs.coveo.com/en/o1ae7549#path-string-required) object The GraphQL API source configuration will be as follows with your Contentful Space ID: ```json "Path": "content/v1/spaces/" ``` ### ["ItemType"](https://docs.coveo.com/en/o1ae7549#itemtype-string-required) object Whether you're using the Contentful GraphQL Content API alone or alongside an existing Contentful CMS, specify the type you want to mark the items to pass from Contentful into the Coveo [index](https://docs.coveo.com/en/204/). In the provided example, the query is configured to fetch articles, and the configuration looks like this: ```json "ItemType": "Article" ``` ### ["Body"](https://docs.coveo.com/en/o1ae7549#body-string) object The body is the full text you want to index. All the text is free-text searchable and available in the [quickview](https://docs.coveo.com/en/3311/) of the index. In the provided example, we assign the HTML body: ```json "Body": "%[body]" ``` ### ["Metadata"](https://docs.coveo.com/en/o1ae7549#metadata-object) object This object gives us the ability to associate some specific properties of each item in the JSON response to a specific field in Coveo. Each key represents the metadata name of the item, while its value is the value path (simple path or JSONPath) in the JSON response. Typically, the value path consists of one or more [dynamic values](https://docs.coveo.com/en/n7jg0349#dynamic-values), since a static, hardcoded value would result in identical metadata for all items. However, you could use a hardcoded value so that the corresponding Coveo field is filled even if the API doesn't provide this information. In the provided example, we take all tags, the slug, all categories, the description, and the image URL. ```json "Metadata": { "articletags": "%[tags[*]]", "cat_slug": "%[slug]", "ec_category": "%[ecCategory[*]]", "ec_description": "%[ecShortdesc]", "ec_shortdesc": "%[ecShortdesc]", "eng_blogimage": "%[engBlogimage.url]", "objecttype": "Article", "thumbnailurl": "%[engBlogimage.url]?w=240" } ``` When you [build your source](https://docs.coveo.com/en/3390#refresh-rescan-or-rebuild-sources), Coveo retrieves the desired metadata. You can then [review a summary of this metadata in the Administration Console](https://docs.coveo.com/en/m9ti0339/) and use it to [create mapping rules](https://docs.coveo.com/en/1640/) for your source. Don't forget to [create a field](https://docs.coveo.com/en/1833#add-a-field) for each metadata name. ### ["PayloadJsonContent"](https://docs.coveo.com/en/o1ae7549#payloadjsoncontent-string) object The `PayloadJsonContent` parameter is a placeholder for your query name that will link to the GraphQL query defined in the **GraphQL queries** section. ```json "PayloadJsonContent": "@query" ```