Meny

This page exists in one language only. Some pages here are English, some Swedish.

Integrations & Embed

This guide is for the developer who puts the Stockisto widget on a website. It covers the script tag, the attributes that configure it, the eight widgets, the public locator endpoints, and analytics consent. For getting retailer data into Stockisto, see the Data Import guide (CSV/XLSX), the Public imports API (NDJSON bundles) or the Public intake API (source-bound batches).


The widget script

The widget is a single, dependency-free script, widget.js, served from the Stockisto CDN. The widget.js address always serves the current deployed build, so your script tag never needs a version bump.

Open a saved embed in your admin and copy its Install snippet. The embed id identifies the widget you saved. This example uses a placeholder id; keep the id and origins your admin generates.

<script
  src="https://cdn.test.stockisto.com/widget.js"
  data-api-base="https://api.test.stockisto.com"
  data-embed="we_0123456789abcdef0123456789abcdef"
  async></script>

Save its type, view, language and settings in Supplier Admin, Retailer Admin or Installer Admin. The installed snippet reads those changes on the next page load. Add only the page keys the page supplies, such as data-sku="YOUR-PRODUCT-CODE". The script inserts its own host; no slot div is needed.

Snippets installed today keep working

Existing attribute snippets still work. Omitted settings come from the owner's default embed; a failed default lookup leaves the existing attribute behaviour intact.

<script
  src="https://cdn.test.stockisto.com/widget.js"
  data-api-base="https://api.test.stockisto.com"
  data-stockisto-slug="YOUR-BRAND-SLUG"
  data-widget-type="where-to-buy"
  async></script>

What the script does

  • Finds its own <script> tag. Async loads are fine: it looks for document.currentScript, then script[data-stockisto-widget="true"], then any script whose src contains widget.js.
  • Resolves data-embed through GET /api/v1/locator/widget-embeds/{publicId} before choosing language, slot, shape or data source. The request is anonymous and sends no cookies.
  • Explicit page attributes override saved values. An empty data-sku suppresses product-dependent rendering.
  • Caches only the loading shape (widgetType, view, settings) under stockisto-embed:<publicId>. A repeat visit can show that skeleton during resolve; cached settings never replace live results.
  • Renders into <div id="stockisto-<data-view>"> when that div exists, else into <div id="stockisto-<data-widget-type>">. With neither, it injects its own host element right after the script tag, so the div is optional.
  • Resolves the embed immediately. Store-result fetching waits until the widget scrolls into view. The asynchronous script does not block page loading.
  • Fails closed. A missing brand, a refused search or an empty result renders an honest empty state or nothing at all. It never throws into your page; boot failures are stamped as data-stockisto-error on the script tag.
  • Adds one <script type="application/ld+json"> block describing the visible store list as a schema.org ItemList of Store nodes. It never emits Product or Offer markup. Turn it off with data-jsonld="off".

Set data-api-base on the TEST environment

Without data-api-base the widget calls https://api.stockisto.com, which is the production origin. Every snippet the dashboard generates carries the right origin for its environment. Keep that line when you copy it.


Configuration attributes

Identity and placement

For new installs use data-embed, the we_ id copied from your saved widget, plus data-api-base. The following attributes describe page overrides and legacy installs. Saved settings fill omitted values; an explicit attribute takes precedence. A named embed does not need a brand slug on the page.

AttributeRequiredDefaultWhat it does
data-stockisto-slugnoYour public brand slug for a legacy install; a named embed supplies it. The widget resolves it through GET /api/v1/locator/brands/{slug}. data-supplier is an accepted alias.
data-supplier-idnoYour supplier tenant GUID, as an alternative to the slug. A non-GUID value is ignored. A GUID embed skips the brand fetch, so it gets no saved theme.
data-api-basenoprod APIThe API origin. Only https://*.stockisto.com origins are accepted; anything else falls back to production.
data-widget-typenowhere-to-buyOne of the eight widgets below. An explicit empty, unknown or retired value renders nothing, so check your spelling.
data-widget-idnorandomA stable id when one page carries several widgets.

Products

AttributeWhat it does
data-skuOne public product code, up to 100 characters. Scopes Where to buy, and required by store-availability and stock-alert. data-product is an alias. An unknown code renders a not-found state, never brand-wide rows.
data-sku-typeDeclares the scheme of data-sku: rsk, gtin (ean accepted), sku, mpn, vvs, nrf, lvi, nobb, finfo, enummer, efo, elnummer_dk, sahkonumero, tun or retailer_sku.
data-skusA comma-separated list of up to 6 codes, forwarded into the store locator's framed search.
data-skus-typeThe scheme for every code in data-skus. One entry that fails the scheme refuses the whole list.

Without a declared scheme the code is tried as rsk, then sku, then gtin. A declared scheme is only ever looked up as that scheme. Classification and certificate codes such as etim, bk04 or va are refused: they are not product keys.

Location and list

AttributeDefaultWhat it does
data-lat / data-lngA fixed search centre in decimal degrees. When set, the widget never asks the browser for location. Results are then always centred on that point, not on the visitor.
data-postcodeA label shown with an explicit centre.
data-radius50Search radius in km. The API accepts 1 to 500.
data-filterWhere to buy: confirmed shows only rows with a confirmed in-stock signal; showroom only showroom rows. Absent shows every row the search returned.
data-rankserverdistance or price. Absent means the server's own ranking (stock first). Price ranking refuses when prices are hidden.
data-per-view3Rows shown before the "see all" footer, 1 to 12 (Where to buy's inline view).
data-max-heightCaps the scrolling store list, 240 to 1200 px.
data-channelonline opens the webshop view first.
data-pricesretaileroff hides published retailer prices; online shows them on webshop rows only. msrp is refused with a console warning, because no suggested retail price exists on the wire.
data-guidedfalseWhere to buy: ask two guided questions before showing rows (requires a resolvable SKU). Excluded by a locator-target pill.
data-sold-outfalseWhere to buy: a "sold out online" banner when nothing in the response is attested in stock.
data-reservefalseWhere to buy: a per-row Reserve action that posts a reservation.
data-pill-targetlocatorWhere to buy pill view: locator links to the hosted brand page, overlay opens the store list overlay.
data-cornerbottom-rightWhere to buy corner view: bottom-right, bottom-left, top-right or top-left.
data-show-hourstrueShow opening hours (store card visit part; the shared store-list expansion).
data-show-servicesfalseShow the showroom or service chip when known.
data-directionstrueShow the Directions link/button.
data-fieldsStore card only: a comma list of hours, phone, directions. The address always shows.
data-exceptionsonStore card only: off hides dated holiday hours.
data-viewWhere to buy: full, inline, button, pill or corner. Store locator: list opens the directory instead of the map.
data-map-height480Frame height for store-locator / installer-finder, 320 to 800 px. Defaults: 480 for the map leg, 560 for the list leg, 640 for installer-finder.
data-serviceinstaller-finder: preselect a service type the brand publishes.
data-audienceWhere to buy: trade sends authorizedOnly=true server-side and keeps wholesalers.
data-quantityWhere to buy: a positive integer quantity filter (requires a resolvable SKU).
data-brandsStore card: up to 12 brand slugs to narrow the brands shown. It can never add a brand the store does not carry.
data-langpageUI language: sv, nb, da or fi. Falls back to <html lang>, then the browser, then English. data-locale is an alias.
data-analytics-consentfalseOnly the literal "true" sends analytics. See below.
data-jsonldonoff disables the structured-data block.

Keys for retailer and installer widgets

AttributeUsed by
data-store-idstore-card, stock-alert: a store location GUID
data-retailerThe retailer's public slug. Required by the three retailer widgets.
data-installerinstaller-card: the installer company GUID

A non-GUID id is dropped and the widget hides itself rather than looping on a 404.

Styling

Every styling attribute is optional. Absent means the Heritage default look.

AttributeValues
data-themeA hex accent (#0057A8), a preset name, or the id of a theme you saved in Supplier Admin
data-theme-presetheritage, light, dark, minimal, dense
data-theme-accent2Secondary accent, hex
data-theme-surfaceCard surface colour, hex
data-theme-inkText colour, hex
data-radius-scalesm, md, lg
data-densitycozy, compact
data-shadowsoft, flat, none
data-fontgrotesk, sans, serif, mono, system. The widget never loads a web font.
data-widthfull, or a pixel value from 200 to 2000

Anything off these lists is dropped. A hex accent with poor contrast against the card is replaced by the default.

Consider a default search centre

Without data-lat/data-lng the widget asks the visitor before it uses browser location, and offers a postcode field instead. If most of your shoppers are in one market, a fixed centre (Stockholm: data-lat="59.3293" data-lng="18.0686") with a generous data-radius shows them stores at once. The trade-off: a fixed centre disables the location prompt entirely.


Widget list

Exactly eight widgets ship. Select one with data-widget-type; an omitted value defaults to where-to-buy, and an explicit empty, unknown or retired value renders nothing. The Supplier Admin Install → Advanced builder generates snippets for the four supplier/brand widgets; Retailer Admin Widgets generates the three retailer widgets; an installer's detail page in Supplier Admin generates the installer widget.

On a supplier's product pages

  • where-to-buy (default): nearby authorized retailers, confirmed stock ranked first. Runs brand-wide, or scoped to one product with data-sku. Five views (data-view): full (the whole list, default), inline (a compact panel in the page's own flow), button (opens an overlay), pill (a compact count pill, "Stocked by N stores near you", degrading to a count-less "Find where to buy" CTA with zero nearby stores, never "0 stores"), corner (a pinned corner pill that opens the list over the page). data-guided, data-sold-out and data-reserve layer optional guided questions, a sold-out-online banner and a reserve action over any view.
  • guided-handoff: a three-step flow. Pick a retailer, optionally pick an approved installer, then give explicit consent before an installer lead is sent.

On a supplier's brand pages

  • store-locator: the whole network as a map, or as a server-rendered directory with data-view="list". Visitors can switch inside the frame.
  • installer-finder: your approved installers with coverage areas, service filters and an in-frame callback request. It never asks for browser location.

On a retailer's own site

All three need data-retailer.

  • store-availability: the retailer's own branches near the shopper with the stock signal for data-sku, and the retailer's published price where the server releases one. Needs data-stockisto-slug, data-retailer and data-sku.
  • store-card: one store's address, opening hours, the brands it carries and its aggregate rating, stacked in that order. Each part hides on its own (data-show-visit / -brands / -rating); with every part off, empty or failed the card hides. Needs data-store-id and data-retailer.
  • stock-alert: a back-in-stock email form for one product at one store. Needs data-stockisto-slug, data-store-id and data-sku. Sign-up is double opt-in.

On an installer's own site

  • installer-card: the installer's registry credential and service-area coverage check, stacked in that order; each section hides on its own (data-show-credential / -coverage). Needs data-installer and the supplier's data-stockisto-slug. The public wire carries a bare certified flag with no supplier, category or date, so it cannot say which brand approved what.

Display signals are server-computed

The In stock / May carry / Contact retailer label comes from the API's displaySignal field and is never re-derived in the browser. The freshness line ("confirmed 3 days ago") is likewise the server's verdict. When the API marks a row isSponsored, the widget always shows a "Sponsored" label.


Content Security Policy

Allow https://cdn.test.stockisto.com in script-src and https://api.test.stockisto.com in connect-src on TEST. For a production snippet, allow https://cdn.stockisto.com and https://api.stockisto.com respectively. Use the origins from your generated snippet. The API origin must be allowed for the embed resolve. The map and installer-finder frames also need frame-src https://find.test.stockisto.com on TEST.

A refused connect-src prevents a named embed from resolving. It shows a load-failed state with Retry; it never renders cached results. A deleted or unknown id renders nothing.


Public locator endpoints

The widget reads from anonymous endpoints under https://api.test.stockisto.com/api/v1/locator. No token or cookie is needed, and any origin may call them. You can call them yourself for a custom integration.

GET /api/v1/locator/search

The widget's main read. It needs the supplier GUID and a search centre:

GET /api/v1/locator/search?supplierId=SUPPLIER_GUID&latitude=59.33&longitude=18.06&radiusKm=50&pageSize=12
ParameterRule
supplierIdRequired. Resolve a brand slug to it with GET /api/v1/locator/brands/{slug} first.
latitude / longitudeRequired unless browse=true. Dot-decimal only. lat and lng are accepted aliases.
radiusKm1 to 500, default 25. radius is an alias.
browse=trueReturns the whole active network without a centre.
skuCodeScope to one public product code. skuCodes takes up to 50 codes for one batched search.
inStockOnly, showroomOnly, authorizedOnlyBoolean filters. authorizedOnly keeps only tiered-relationship stockists.
page, pageSizeZero-based page; pageSize defaults to 50.

Each retailer row carries id, retailerId, slug, name, address, city, postalCode, country, latitude, longitude, distanceKm, isShowroom, phone, email, website, openingHours, displaySignal, rankingScore, isSponsored, isSample and a stockStatus object (freshness, lastVerifiedAt, confidenceTier). The envelope adds totalCount and hasMore. displaySignal is InStock, MayCarry or ContactRetailer. Results are cached for five minutes per supplier.

Coordinates are always dot-decimal

Write latitude=59.33, never 59,33. A search without a usable centre returns HTTP 400 rather than silently searching at (0,0).

Other routes the widget uses

RoutePurpose
GET /api/v1/locator/brands/{slug}Brand theme and supplier id for a slug. Cached ten minutes.
GET /api/v1/locator/retailers/{slug}/storesA retailer's own stores. A centre is optional here.
GET /api/v1/locator/find/stores/{id}One store's detail: address, structured hours, brands carried.
GET /api/v1/locator/find/stores/{id}/reviewsThe store's rating aggregate.
GET /api/v1/locator/find/installers/{id}One installer's coverage areas and registry certification.
GET /api/v1/locator/{supplierSlug}/installers?take=5Approved installers for the guided handoff.
POST /api/v1/installers/companies/{id}/leadsSends the guided-handoff lead once the visitor consents.
POST /api/v1/locator/stock-alertsBack-in-stock sign-up. 202 means a confirmation email was sent, not a live alert.
POST /api/v1/locator/reservationsA reservation request from data-reserve.
GET /api/v1/locator/geocode?q=…Postcode and address geocoding, Nordic countries only. 20 requests per minute per IP.
GET /api/v1/locator/resolve-host?host=…Maps a verified custom domain to { supplierId, slug }. No DNS lookup happens here.

Status codes to handle

StatusMeaning
400Missing or invalid parameters, for example no latitude.
403The locator is set to Private, or the widget type is above the supplier's plan.
429Rate limit hit. Honor Retry-After.
503The supplier tenant is suspended.

Rate limits

/locator/search allows 100 requests per minute per tenant and 20 per minute per anonymous IP. /locator/brands/{slug} allows 500 per minute. Store and installer detail reads allow 80 per minute per anonymous IP.


Analytics events

With data-analytics-consent="true" the widget posts events to POST https://api.test.stockisto.com/api/v1/analytics/events. It uses fetch with keepalive and no credentials, so no cookie ever travels with an event.

The body carries schemaVersion: 1, sessionId, correlationId, eventType and a payload. The server resolves your tenant from the brand slug and ignores any tenant id in the body. It answers 202 Accepted without waiting for the write. Anonymous callers may only send known event types; an unknown type returns 400.

Events are credited to your account only when the page's origin is on your Allowed origins list (Supplier Admin → Install → Embed script). Add every domain that hosts the widget, one per line, such as https://www.yourbrand.com. The same list gates lead attribution for the guided handoff.

Consent gating

With the default data-analytics-consent="false" the widget sends no analytics at all and writes nothing to session storage. Set it to "true" only after your consent tool has recorded a lawful basis.


Installing through a tag manager or a CMS

Content-Security-Policy

If your site sends a CSP header, add https://cdn.test.stockisto.com to script-src and https://api.test.stockisto.com to connect-src. The framed widgets (store-locator, installer-finder) also need the locator host in frame-src.

What's next?

cebf50c · 2026-10-05 22:57