Skip to content

Django / Jinja

Markdown

SSR, script, signed-in customer and order detail integration for a store built with Django or Jinja templates.

This page is for stores built with Django or Jinja templates. The Django kit provided by the Sayproof team brings the server call, caching, failure handling and template helpers ready made. The kit is copied into the store project; it needs no package installation and uses only Django and Python’s standard library. It works with Python 3.9 and Django 2.2 and newer versions.

The same template works with both methods; the only difference is the server key:

  • SSR (recommended): When a server key is set, reviews are fetched on the server as ready HTML and are part of the page’s first response. Search engines see the review text and rating without waiting for the script; the script takes over the section once it loads. Details: Server-side rendering.
  • Script: When no server key is set, an empty container is printed and the script fetches reviews in the browser. The server makes no call to Sayproof. To switch to SSR later, only the server key is added.
  1. Copy the kit’s sayproof folder into your project’s app (for example store_app/sayproof/). The platform’s own folders are not changed; the kit is only added to your app.

  2. Define the settings:

    SAYPROOF_BASE = os.environ.get("SAYPROOF_BASE", "")
    SAYPROOF_SITE_KEY = os.environ.get("SAYPROOF_SITE_KEY", "")
    SAYPROOF_SSR_KEY = os.environ.get("SAYPROOF_SSR_KEY", "")
    SAYPROOF_CHANNEL = os.environ.get("SAYPROOF_CHANNEL", "web")

    The Sayproof address, the Site key and the Channel code are shown with copy buttons in the Values for the setup list when Django / Jinja (on the server) is selected as the Setup route on the Integration › Showing reviews tab in the panel. The server key is not shown there; it is created on the Channels › Keys tab and appears only once, when it is created. The server key is kept only in the server’s environment variables; it is never written into a template or the browser.

  3. Register the template helpers in the Jinja environment’s globals. If your settings file updates the globals with a dictionary (for example GLOBAL_OPTIONS.update({...})), add these lines:

    GLOBAL_OPTIONS.update({
    "sayproof_ssr": "store_app.sayproof.markup.sayproof_ssr",
    "sayproof_reviews": "store_app.sayproof.markup.sayproof_reviews",
    "sayproof_script": "store_app.sayproof.markup.sayproof_script",
    "sayproof_rating": "store_app.sayproof.markup.sayproof_rating",
    "sayproof_json_ld": "store_app.sayproof.markup.sayproof_json_ld",
    "sayproof_order_reviews": "store_app.sayproof.markup.sayproof_order_reviews",
    })

    Projects that set up their own Jinja environment add the JINJA_GLOBALS dictionary to the environment’s globals. In the Django template language the same names are used after {% load sayproof_tags %}.

Optional settings:

Setting Default Use
SAYPROOF_SERVER_BASE SAYPROOF_BASE When the server reaches Sayproof at a different address than the browser
SAYPROOF_SCRIPT SAYPROOF_BASE + /storefront/sayproof.js When the script is served from a CDN
SAYPROOF_TIMEOUT 1.5 Timeout of the SSR call (seconds)
SAYPROOF_VIEWER_TIMEOUT 3 Timeout of the signed-in customer and order detail requests (seconds)
SAYPROOF_CACHE_SECONDS 60 How long an SSR response stays in the cache
SAYPROOF_FAILURE_SECONDS 10 How long to wait before trying again when Sayproof cannot be reached
SAYPROOF_VIEWER_URL /sayproof/viewer/ Address of the signed-in customer endpoint
SAYPROOF_CUSTOMER_EMAIL request.user.email Path of the function that reads the signed-in customer’s email address
SAYPROOF_CUSTOMER_NAME (none) Path of the function that reads the name shown next to a question; without it the question shows without a name (Signed-in customers › Questions and answers)
{% set reviews = sayproof_ssr(product.sku, product.name) %}
{{ sayproof_reviews(product.sku, product.name, ssr=reviews) }}
{{ sayproof_script() }}
  • The sayproof_ssr response is fetched once and used for both the section and the structured data. The same product’s response comes from the cache for 60 seconds.
  • The product code must match the key in your product source and the line code in the order.
  • To show reviews for all colours and sizes of a product together, pass the group code with scope="group".
  • sayproof_script() appears once on the page.
  • If you draw the review section with your own components, pass headless=True; only the state tag is written into the container instead of HTML. See Headless.

If the page already has the product’s Product JSON-LD, no second Product is added; the rating is added to the existing object:

{{ sayproof_json_ld(sayproof_rating(product_json_ld, reviews)) }}

If the page has no Product JSON-LD:

{% if reviews %}{{ sayproof_json_ld(reviews.json_ld) }}{% endif %}

sayproof_json_ld escapes customer texts so they cannot break out of the tag even if they contain </script>.

  1. Connect the kit’s endpoint: path("", include("store_app.sayproof.urls")).
  2. Pass viewer=True on the product page: sayproof_reviews(product.sku, product.name, ssr=reviews, viewer=True).

The customer’s state is not written into the page; the browser asks /sayproof/viewer/, and the store server forwards the question to Sayproof with the server key. The page stays cacheable. The email address is read from request.user.email by default; if the session information is elsewhere, define your own function with SAYPROOF_CUSTOMER_EMAIL. If the function returns an empty text, the customer is treated as anonymous and no call is made to Sayproof. Details: Signed-in customers.

{{ sayproof_order_reviews(order.number, customer_email) }}
{{ sayproof_script() }}

If the order is not found in Sayproof or belongs to another customer, nothing is printed. This call is not cached.

If the page uses a CSP nonce, pass the nonce parameter to sayproof_script, sayproof_reviews (with viewer=True) and sayproof_json_ld. script-src and connect-src must include the Sayproof address.

  • If the SSR call does not answer within 1.5 seconds or returns anything other than 200, the container is printed empty and the script fetches reviews in the browser.
  • The failure is kept in the cache for 10 seconds, so page loads do not wait again while Sayproof cannot be reached.
  • The page does not break even if the cache is not working.
  • Logs contain only the called path and the type of error; customer emails and keys are never logged.