Skip to content

Injections

Injection apps render small HTML snippets — analytics pixels, chat widgets, consent banners — directly into the storefront without writing any Twig theme code. The snippet is declared in your manifest and is rendered server-side on every storefront page load for each host that has your app installed.

How it works

 Host installs your app and fills in settings (e.g. "Tracking ID: UA-1234")

 Guest visits any storefront page

 Stayblox renders the page

   ├── Reads all active app installs for this team
   ├── For each install with injections:
   │     interpolates {{ setting_key }} placeholders from install settings
   │     and drops the rendered HTML into the named slot

   └── Page delivered to guest with all injection snippets inline

The injection is rendered per-install, so each host's snippet carries their own tracking ID, chat token, or other per-install setting values.

Declaring injections in the manifest

Add an injections array to your manifest. Each entry specifies a slot (where on the page) and a template (what to insert):

jsonc
{
  "scopes": [],
  "settings_schema": [
    { "key": "tracking_id", "type": "string", "label": "Google Analytics Tracking ID", "required": true }
  ],
  "injections": [
    {
      "slot": "head",
      "template": "<!-- Google Analytics -->\n<script async src=\"https://www.googletagmanager.com/gtag/js?id={{ tracking_id }}\"></script>\n<script>\n  window.dataLayer = window.dataLayer || [];\n  function gtag(){dataLayer.push(arguments);}\n  gtag('js', new Date());\n  gtag('config', '{{ tracking_id }}');\n</script>"
    }
  ]
}

You can declare multiple injections (e.g. one in head, one in body_end):

jsonc
"injections": [
  { "slot": "head",     "template": "<link rel=\"preconnect\" href=\"https://widget.example.com\">" },
  { "slot": "body_end", "template": "<script src=\"https://widget.example.com/chat.js?token={{ api_token }}\"></script>" }
]

Slots

SlotPosition in the storefront
headInside <head>, after platform styles and scripts.
body_endImmediately before </body>. Preferred for JavaScript that doesn't need to block rendering.

Slot names must be known values — unknown slots are rejected at manifest validation. As new slots are added to the platform, the manifest validator is updated first.

Template interpolation

Templates may contain placeholders. At render time, Stayblox replaces each placeholder with the value from the install's settings (what the host entered during installation). Only keys declared in settings_schema are available.

html
<!-- {{ tracking_id }} becomes e.g. "UA-9876543-2" per install -->
<script src="https://cdn.example.com/widget.js?key={{ tracking_id }}"></script>

If a setting key is missing or blank (the host hasn't filled it in), the placeholder resolves to an empty string. Design your snippet to degrade gracefully in that case.

Interpolation is intentionally minimal. Only setting values from the install are available — not booking data, property data, or any other runtime context. If you need dynamic runtime data in your script, fetch it from your own server using a value (e.g. an API key or token) that came from settings.

Security and review

Injection templates are reviewed as part of the app review process. The review checks that:

  • External resources (src, href) load from a declared https:// origin.
  • No inline JavaScript (<script> blocks without a src) are present — these cannot be attributed to a specific origin and are routinely rejected by Content Security Policies.
  • No javascript: URI scheme anywhere in the template.
  • No <iframe> elements (use Embedded pages for that).

The platform also strips elements the sanitizer considers risky on final render. Build your injection to rely solely on external resources from your own https:// CDN.

Pure injection apps

An injection app can have scopes: [] and no webhooks entry — it doesn't need API access at all. The install flow shows a minimal consent screen (just the settings form, no scope list), and no API token or webhook secret is generated. This is the right shape for analytics pixels and simple script loaders.

jsonc
{
  "name": "My Analytics Pixel",
  "description": "Track storefront visits with My Analytics.",
  "scopes": [],
  "settings_schema": [
    { "key": "site_id", "type": "string", "label": "Site ID", "required": true }
  ],
  "injections": [
    {
      "slot": "head",
      "template": "<script src=\"https://myanalytics.example.com/pixel.js?sid={{ site_id }}\"></script>"
    }
  ]
}

Injections in general-purpose apps

Injections are not exclusive to type: injection apps. Any app type can include an injections array. A smart-lock app might declare type: remote, handle webhooks, write metafields, and inject a check-in widget into the storefront — all from one app.

Checklist

  • [ ] slot is a known value (head, body_end).
  • [ ] All external resources load from a fixed https:// domain.
  • [ ] No inline <script> blocks (use <script src="..."> instead).
  • [ ] Setting keys referenced in templates are declared in settings_schema.
  • [ ] Snippet degrades gracefully when a setting is empty.

© Stayblox — Developer Platform