SSR API (IN BETA)

The Feefo Server-Side Rendering (SSR) API allows you to inject Feefo review structured data directly into the HTML generated by your server using Schema.org JSON-LD.

This structured data can represent:

  • Product ratings and product reviews
  • Service ratings and service reviews
  • Merchant organisation information
  • AI-generated product review summaries and review topics (where enabled)

Available Resources

EndpointSchema.org TypePurpose
GET /widgets-review-service/ssr/productProductProduct ratings, reviews, and AI summaries
GET /widgets-review-service/ssr/serviceOrganizationMerchant info, service ratings, and service reviews

The returned JSON payload should be injected into your server-rendered HTML inside a <script type="application/ld+json"> tag.


Before You Start

To integrate with the SSR API, ensure you have:

  1. A Feefo App Key with the SSR API option enabled.
  2. An OAuth 2.0 access token generated using your App Key credentials.
  3. Your Feefo merchant slug.
  4. The relevant widget type (e.g., on-page or pop-up).
  5. (For product requests) A product sku, parent_sku, or SERIES tag.

Enable SSR API Access

App Keys are managed inside the Feefo Hub:

  1. Navigate to Settings → Connectivity → App Keys.
  2. Create a new App Key or edit an existing one.
  3. Enable the SSR API option.
👍

Principle of Least Privilege

We recommend granting an App Key access only to the specific Feefo services required by your integration.


Authentication

Feefo APIs authenticate via OAuth 2.0. Use the Client ID and Client Secret associated with your App Key to generate a Bearer token.

Request Access Token

POST [https://api.feefo.com/api/oauth/v2/token](https://api.feefo.com/api/oauth/v2/token)
Content-Type: application/json
{
  "client_id": "your-client-id",
  "client_secret": "your-client-secret",
  "grant_type": "client_credentials"
}

Token Response

{
  "access_token": "your-access-token",
  "expires_in": 3600,
  "token_type": "bearer"
}
  • expires_in indicates the token lifetime in seconds. When the token expires, request a new one using the same credentials.
  • Pass the token in the Authorization header of all SSR requests:
Authorization: Bearer your-access-token
❗️

Keep Credentials Server-Side

Never expose your client_secret or access_token in client-side browser JavaScript. OAuth token generation and SSR API calls must only happen in a trusted server environment.


Product Structured Data

Retrieve Schema.org Product structured data for an individual product, parent product, or product series.

GET /widgets-review-service/ssr/product

Query Parameters

ParameterRequiredDescription
slugYesYour Feefo merchant slug.
widgetYesWidget type/configuration (e.g., on-page, pop-up).
skuConditionalIndividual product SKU.
parent_skuConditionalParent product SKU.
schema_idNoThe exact @id URI of your existing on-page Product schema (URL-encoded). When provided, Feefo targets this ID to merge review ratings with your existing product schema. If omitted, a stable fallback @id is generated automatically.
tagsNoRestricts ratings, reviews, and AI content to reviews carrying the specified tag (key:value). Repeat the parameter to supply multiple tags.
📘

Product Identifier Requirement

You must supply at least one of the following: sku, parent_sku, or a tags parameter with the key SERIES (e.g., tags=SERIES:my-series).

Example Requests

Standard SKU Request:

GET /widgets-review-service/ssr/product?slug=your-merchant&sku=ABC123&widget=on-page
Authorization: Bearer your-access-token

Parent SKU Request:

GET /widgets-review-service/ssr/product?slug=your-merchant&parent_sku=PARENT123&widget=on-page
Authorization: Bearer your-access-token

SERIES Tag Request (instead of SKU):

GET /widgets-review-service/ssr/product?slug=your-merchant&widget=on-page&tags=SERIES:my-series
Authorization: Bearer your-access-token

Example Product Response (200 OK)

Up to five eligible reviews are included in the response. Exact fields depend on available product and review data.

{
  "@context": "[https://schema.org](https://schema.org)",
  "@type": "Product",
  "@id": "[https://www.example.com/products/example-product#Product](https://www.example.com/products/example-product#Product)",
  "name": "Example Product",
  "description": "Example product description",
  "aggregateRating": {
    "@type": "AggregateRating",
    "bestRating": 5,
    "worstRating": 1,
    "ratingValue": 4.7,
    "reviewCount": 124
  },
  "review": [
    {
      "@type": "Review",
      "author": {
        "@type": "Person",
        "name": "Trusted Customer"
      },
      "reviewRating": {
        "@type": "Rating",
        "bestRating": 5,
        "worstRating": 1,
        "ratingValue": 5
      },
      "reviewBody": "An example customer review.",
      "datePublished": "2026-01-15T10:30:00Z",
      "publisher": {
        "@type": "Organization",
        "@id": "[https://www.feefo.com/#organization](https://www.feefo.com/#organization)",
        "name": "Feefo",
        "url": "[https://www.feefo.com](https://www.feefo.com)"
      },
      "url": "[https://www.feefo.com/example-review](https://www.feefo.com/example-review)",
      "@id": "[https://www.feefo.com/example-review#review](https://www.feefo.com/example-review#review)",
      "inLanguage": "en-GB",
      "itemReviewed": {
        "@id": "[https://www.example.com/products/example-product#Product](https://www.example.com/products/example-product#Product)"
      }
    }
  ]
}

AI Product Review Content

Depending on your Feefo configuration and widget type, the product response may include AI-generated review summaries (additionalProperty) and review topics (positiveNotes / negativeNotes):

{
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "name": "Customer review summary",
      "value": "Customers frequently praise the product's quality and ease of use."
    },
    {
      "@type": "PropertyValue",
      "name": "Review summary source",
      "value": "Feefo verified customer reviews"
    }
  ],
  "positiveNotes": {
    "@type": "ItemList",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": 1,
        "name": "Quality"
      },
      {
        "@type": "ListItem",
        "position": 2,
        "name": "Ease of use"
      }
    ]
  }
}

(Negative topics follow the exact same ItemList structure under negativeNotes. These fields are omitted if AI features are disabled for the widget or insufficient data exists.)

Schema @id and Graph Linking

Search engines use the Schema.org @id property as a primary key to connect separate JSON-LD blocks describing the same entity:

  • If you already render Product JSON-LD on your page: Pass the exact @id from your existing <script type="application/ld+json"> node into the schema_id query parameter (URL-encoded). Search engines will merge Feefo’s ratings and reviews with your price, availability, and image metadata.
  • If you do not render existing Product JSON-LD: Omit schema_id. Feefo will generate a stable fallback @id.

Service Structured Data

Retrieve Schema.org Organization structured data representing your business and service reviews.

GET /widgets-review-service/ssr/service

Query Parameters

ParameterRequiredDescription
slugYesYour Feefo merchant slug.
widgetYesWidget type/configuration (e.g., on-page, pop-up).
tagsNoRestricts ratings and reviews to reviews carrying the specified tag (key:value). Repeat the parameter to supply multiple tags.

Example Request

GET /widgets-review-service/ssr/service?slug=your-merchant&widget=on-page
Authorization: Bearer your-access-token

Example Service Response (200 OK)

Up to five eligible service reviews are included. Fields such as address, telephone, image, and url depend on the merchant details configured in your Feefo account.

{
  "@context": "[https://schema.org](https://schema.org)",
  "@type": "Organization",
  "@id": "[https://www.feefo.com/en-GB/reviews/example-merchant](https://www.feefo.com/en-GB/reviews/example-merchant)",
  "sameAs": "[https://www.feefo.com/en-GB/reviews/example-merchant](https://www.feefo.com/en-GB/reviews/example-merchant)",
  "url": "[https://www.example.com](https://www.example.com)",
  "image": "[https://api.feefo.com/api/merchant-image/example-logo.png](https://api.feefo.com/api/merchant-image/example-logo.png)",
  "name": "Example Merchant",
  "aggregateRating": {
    "@type": "AggregateRating",
    "bestRating": 5,
    "worstRating": 1,
    "ratingValue": 4.8,
    "reviewCount": 1500
  },
  "review": [
    {
      "@type": "Review",
      "author": {
        "@type": "Person",
        "name": "Trusted Customer"
      },
      "reviewRating": {
        "@type": "Rating",
        "bestRating": 5,
        "worstRating": 1,
        "ratingValue": 5
      },
      "reviewBody": "Excellent service.",
      "datePublished": "2026-01-15T10:30:00Z",
      "publisher": {
        "@type": "Organization",
        "@id": "[https://www.feefo.com/#organization](https://www.feefo.com/#organization)",
        "name": "Feefo",
        "url": "[https://www.feefo.com](https://www.feefo.com)"
      }
    }
  ],
  "address": {
    "@type": "PostalAddress",
    "addressCountry": "GB",
    "addressLocality": "London",
    "addressRegion": "Greater London",
    "postalCode": "AB1 2CD",
    "streetAddress": "1 Example Street"
  },
  "telephone": "01234567890"
}

Filtering by Tags & Widget Configuration

Filtering by Tags

The tags parameter works identically across both /product and /service endpoints:

  • Format: Must use key:value syntax (e.g., tags=incentivised:1). Supplying a tag without a value (e.g., tags=incentivised) returns 400 Bad Request.
  • Multiple tags: Repeat the query parameter (tags=incentivised:1&tags=colour:red). Order does not matter.
  • AND logic: When multiple tags are provided, a review must carry all specified tags to be included.
  • Scope: Tag filtering applies to the aggregateRating, reviewCount, review array, and (for products) AI summaries and topics.
GET /widgets-review-service/ssr/product?slug=your-merchant&sku=ABC123&widget=on-page&tags=incentivised:1&tags=colour:red

Understanding the widget Parameter

The widget parameter (e.g., widget=on-page or widget=pop-up) tells Feefo which widget configuration and customisations to apply when generating structured data—including whether AI summaries or topics are enabled. Always pass the widget type matching the Feefo widget rendered on that page.


Response Statuses & Caching Behaviour

Status CodeMeaningBehaviour & Action Required
200 OKStructured data is ready.Inject the JSON response body into your page HTML inside a <script type="application/ld+json"> tag.
204 No ContentData is currently being generated asynchronously.Returns an empty body with Cache-Control: no-store. Do not cache 204 responses. Render the page without Feefo JSON-LD and retry on a subsequent request.
400 Bad RequestMissing or invalid parameters.Verify slug and widget are present, product requests include sku/parent_sku/SERIES, and all tags follow key:value format.

Asynchronous First-Request Flow

Feefo generates SSR payloads asynchronously per unique combination of parameters (including distinct tag combinations). The first time a unique combination is requested, the API triggers generation and returns 204 No Content:

Your Server                            Feefo SSR API
     |                                       |
     |--- GET /ssr/product (1st request) --->|
     |<-- 204 No Content --------------------|  (Triggers async generation)
     |                                       |
     |    ... (SSR payload generated) ...    |
     |                                       |
     |--- GET /ssr/product (later request) ->|
     |<-- 200 OK (Schema.org JSON-LD) -------|
🚧

Handling 204 Responses

  • Do not treat 204 No Content as an application error.
  • Do not cache 204 responses.
  • Do not retry in a tight synchronous loop during page load—either wait for a subsequent page render or use bounded background polling.

Automatic Data Refresh

Feefo stores generated SSR results and periodically refreshes them asynchronously without blocking live requests. Because SSR endpoints are not served from a CDN cache, you do not need to manage cache invalidation when new reviews arrive.


Adding the Response to Your Page

Serialise the 200 OK JSON response into a <script type="application/ld+json"> tag in your HTML <head> or <body>. Do not render the JSON as visible page text.

📘

Required Script id Prefix

To allow Feefo's client-side widget to detect existing server-rendered schema and avoid duplicate injection, include an id attribute on the <script> tag using the appropriate prefix (you may append any unique suffix):

  • Product schema: id="onpage-product-schema-<suffix>"
  • Service schema: id="onpage-organization-schema-<suffix>"

Example HTML Implementation

<!doctype html>
<html lang="en">
<head>
  <title>Example Product</title>
  <script id="onpage-product-schema-ABC123" type="application/ld+json">
  {
    "@context": "[https://schema.org](https://schema.org)",
    "@type": "Product",
    "@id": "[https://www.example.com/products/example-product#Product](https://www.example.com/products/example-product#Product)",
    "name": "Example Product",
    "aggregateRating": {
      "@type": "AggregateRating",
      "bestRating": 5,
      "worstRating": 1,
      "ratingValue": 4.7,
      "reviewCount": 124
    }
  }
  </script>
</head>
<body>
  <!-- Page content -->
</body>
</html>

Recommended Server-Side Flow

  1. Receive an incoming page request on your server.
  2. Call GET /widgets-review-service/ssr/product (or /service) with Authorization: Bearer <access-token>, matching your on-page widget and tags.
  3. If 200 OK: Inject the returned JSON into <script id="onpage-product-schema-..." type="application/ld+json">.
  4. If 204 No Content (or timeout): Render the HTML page without the Feefo JSON-LD block and allow subsequent requests to fetch it once generated.
  5. Return the completed HTML document.

Integration Best Practices

  • Enforce strict HTTP timeouts (~100ms): Because SSR requests run during server page generation, upstream latency can impact Time to First Byte (TTFB). Set a strict timeout (recommended ~100ms). If the request times out or fails, abort and render the page without the JSON-LD block.
  • Rely on the safe client-side fallback: If the SSR request returns 204 or times out, your site is unaffected—the embedded client-side Feefo widget automatically detects the missing script id and injects Schema.org JSON-LD in the browser.
  • Match widget type and tags: Always send the exact same widget value and tags to the SSR API as your on-page Feefo widget so server-rendered structured data matches visible reviews.
  • Do not alter review data: Insert the Schema.org JSON payload verbatim without modifying ratings, review counts, author names, or review text.

Quick Reference Summary

EndpointRequired ParamsOptional ParamsReturns
GET /widgets-review-service/ssr/productslug, widget, + at least one of: sku, parent_sku, or tags=SERIES:<val>schema_id, tags (key:value, repeatable)Schema.org Product
GET /widgets-review-service/ssr/serviceslug, widgettags (key:value, repeatable)Schema.org Organization

Did this page help you?