# Setting up with the script

> Displaying reviews on any site with a single script tag and a container.

Source: /en/integrate/script/

This is the shortest setup method and it works on any site: the Sayproof script is added to the page, together with a container where the reviews are to be shown. The script fetches the reviews, builds the summary, the photo strip and the list, and manages filters, search, sorting, "Helpful?" votes, reports, the photo viewer and the review writing flow. No framework such as React or Vue is required.

## Adding the script

Add the following at the end of the page, before the `</body>` tag:

```html
<script type="module"
        src="https://cdn.sayproof.example/sayproof.js"
        data-review-site-key="YOUR-SITE-KEY"
        data-review-base="https://api.sayproof.example"
        data-review-locale="en"></script>
```

| Attribute | Description |
|---|---|
| `src` | The script's address. The actual address is shown in the **Script address** row of the **Values for the setup** list on the **Show reviews on the product page** card on the **Integration › Showing reviews** tab in the panel when the **Script (in the browser)** route is chosen. |
| `data-review-site-key` | Your channel's site key. |
| `data-review-base` | The Sayproof API address. |
| `data-review-locale` | `tr` or `en`. If omitted, the page's `<html lang>` value is used, and failing that the channel's language. |

The script is an ES module and is loaded over CORS; `type="module"` is therefore required. Adding it once per page is sufficient.

## Adding the container

Add the following element where the reviews are to be shown:

```html
<div data-review-mount
     data-review-product="PRODUCT-CODE"
     data-review-product-name="Product name"></div>
```

| Attribute | Description |
|---|---|
| `data-review-mount` | Marks the element as a review container. |
| `data-review-product` | The product code. It must be **the same** as the `variant_key` (or `group_key` for group-level display) sent in the order transfer. |
| `data-review-scope` | `variant` (default): only this variant's reviews. `group`: all reviews of the product group; in this case `data-review-product` is the group code. |
| `data-review-product-name` | The product name. Optional. |
| `data-review-layout` | `list` (default) or `grid`. |
| `data-review-style` | `cards` or `sidebar`: the layout of the review section. If omitted, the layout chosen for the channel in the panel is used. See [Layout and CSS selectors](/en/customize/css-hooks.md). |
| `data-review-theme` | `warm`, `trust`, `editorial`, `minimal`, `soft`, `bold`, `natural` or `night`: the built-in design of the review section. If omitted or not recognised, the design chosen for the channel in the panel is used. |
| `data-review-gate` | If the review writing area is to be shown somewhere other than inside the container, the CSS selector of that place, for example `#write-review`. |

A page can contain several containers; each container shows the reviews of its own product.

## Page changes

The script watches the page for changes. If a container is added or removed later, or if the `data-review-product` value changes (for example when a variant is selected), the component updates itself. Single-page applications (SPAs) require no additional work.

When manual control is needed, the script's public API is the `window.Sayproof` object:

```js
window.addEventListener("sayproof:ready", () => {
  const container = document.querySelector("#reviews");
  window.Sayproof.update(container, { product: "PRODUCT-CODE-2" });
});
```

For all methods, see [JavaScript API](/en/reference/javascript-api.md).

## The review writing flow

The default component does **not** show a general "Write a review" button to visitors who are not signed in; doing so would steer people who have not bought the product towards writing a review. Instead, a short note and the "Verify my order to write a review" link are shown:

1. The customer enters the order number and the email address used for the order.
2. Sayproof checks the order: whether the payment is complete, whether the product has been delivered, whether the time allowed to write has expired and whether this line has already been reviewed.
3. If the conditions are met, the review form opens. If not, a single general error message is shown; a missing order and an incorrect email address are not distinguished from each other.

A customer arriving through the link in an invitation email does not need this verification: the script detects the `#review_token=…` part of the link (the `?review_token=…` parameter in older invitations), removes it from the address bar and opens the form automatically. In a shopping experience invitation sent for a cancelled or returned order, the form opens without rating topics. For signed-in customers, see [Signed-in customers](/en/integrate/signed-in-customers.md).

When the customer adds a photo or video, the script prepares the file in the browser before uploading it. A photo is scaled so that its long side is at most 2,560 pixels and saved again as JPEG (as WebP or PNG when it has transparent areas); this also drops the location and device information the photo carries. A video is converted to H.264 with its short side at most 1,080 pixels, about 3 Mbps and at most 30 frames per second, without sound and without its location tags; a video that already fits these values is not re-encoded, only its sound and tags are removed. A video longer than the limit is not converted. While this happens the file shows "Preparing 42%" and then "Uploading 17%" next to a button that cancels it. If the browser cannot prepare a file, for example a HEIC photo in a browser that cannot read it or a browser that cannot encode video (a video conversion that makes no progress for 20 seconds, or takes more than 4 minutes in total, is also treated as not prepared and is stopped), the original is uploaded when it is within the size limit; otherwise the form says the file cannot be reduced in this browser and does not upload it.

## Content Security Policy (CSP)

If your site uses a CSP:

- The `script-src` directive must include the script's address, and the `connect-src` directive the Sayproof API address.
- The `img-src` and `media-src` directives must include the address from which review photos and videos are served.
- If you use server-side rendering, the `style-src` directive must allow the `sayproof.css` file served from the same address as the script.
- If you use a nonce, add the `nonce` attribute to the script tag. The script adds its styles in `<style>` elements (`#sayproof-style`; `#sayproof-style-form` when the form first opens or the reviews on the order page are built, and `#sayproof-style-lightbox` when the photo viewer first opens) and also writes the tag's nonce value to these elements. If your `style-src` directive does not allow `'unsafe-inline'`, the nonce is required: without it the browser blocks these styles and the component and the review form appear unstyled.

## Performance

The script's initial load is about 13 KB (gzip). The default component's styles are a separate chunk that loads in parallel with the first review list request (about 6 KB); the component is drawn once, when both the list response and the styles are ready. In headless use these styles are not loaded at all. The review form is a separate chunk that is only loaded when the form opens (about 7.5 KB, including the dialog part it shares with the photo viewer). The photo viewer is also a separate chunk, loaded only when a photo or video is first opened (about 1.5 KB; about 3 KB together with the shared dialog part if the form has not been opened before). When a visitor chooses a photo or video, one more chunk is loaded for preparing it (about 2.3 KB); the first time a video is chosen and the browser can encode video, a second chunk with the video converter is loaded (about 100 KB). Neither is loaded unless a file is chosen. Requests send no cookies, and read requests do not trigger a browser preflight request.

`sayproof.js` and `sayproof.css` are cached for 5 minutes; a new release reaches your site within a few minutes and you don't need to change the address. The other chunks the script loads change name with their content and stay cached for a year. Files are served with the compression the browser supports (brotli or gzip).

## Product page views

For each container, once per page load, the script notifies Sayproof that the product was viewed. This count is used for the "reviews per 1,000 views" figure on the **Statistics › Product ratings** tab. The notification is anonymous: no person, cookie, IP address or browser details are stored, and bot, link preview and prefetch requests are not counted. On a prerendered page, the notification is sent when the page is actually shown.

## Test

Open a product page, then check the "Seen on your site?" section on the **Integration › Showing reviews** tab in the panel. If reviews do not appear, see [Troubleshooting](/en/integrate/troubleshooting.md).
