Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .changeset/hydrogen-wrapper-prompt.md

This file was deleted.

13 changes: 1 addition & 12 deletions templates/install-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Determine whether the capture snippet is *actually* installed. The snippet is th

Run these checks in order. Stop at the first positive match.

1. Package dependencies (highest confidence) — Read `package.json`. Look for `@fullstory/browser`, `@fullstory/react-native`, `@fullstory/snippet`, or `@subtextdev/hydrogen` in `dependencies` or `devDependencies`.
1. Package dependencies (highest confidence) — Read `package.json`. Look for `@fullstory/browser`, `@fullstory/react-native`, or `@fullstory/snippet` in `dependencies` or `devDependencies`.
2. Script tag in HTML entry point — Search ONLY the HTML entry point (`index.html`, `app/layout.tsx`, `pages/_document.tsx`, or framework equivalent) for the literal strings `fullstory.com/s/fs.js` or `_fs_script`. Do not search other files.
3. SDK initialization call — Grep for `init\(\s*\{\s*orgId`, `window\['_fs_org'\]\s*=`, or `window\._fs_org\s*=` in `.ts`, `.tsx`, `.js`, `.jsx` files (exclude `node_modules`, test files, and `*.d.ts`). The `init()` call comes from `@fullstory/browser` v2: `import { init } from '@fullstory/browser'`.

Expand All @@ -45,7 +45,6 @@ Before making any changes, do a read-only pass to gather what the install will d

Read `package.json` and project structure to detect the framework:

- `@shopify/hydrogen` in dependencies → Shopify Hydrogen → wrapper-package install, see "Shopify Hydrogen" under Framework patterns. Check this FIRST: Hydrogen apps also contain Remix/React Router and Vite dependencies, which must not shadow this match.
- `next` in dependencies → Next.js (App Router) → `app/layout.tsx`
- `next` + `pages/_document.tsx` exists → Next.js (Pages Router) → `pages/_document.tsx`
- `@remix-run/*` in dependencies → Remix → `app/root.tsx`
Expand Down Expand Up @@ -100,16 +99,6 @@ This is the snippet to install. It is specific to this organization — install

### Framework patterns

- Shopify Hydrogen — Do NOT paste the raw snippet. Install the wrapper package instead; it handles the snippet, Hydrogen's nonce-based CSP, and consent gating through Shopify's Customer Privacy API:
1. `npm install @subtextdev/hydrogen` (match the project's package manager: pnpm/yarn/bun if a corresponding lockfile exists).
2. Derive the configuration from the snippet in Step 4 above — do not invent values: `orgId` is the `window['_fs_org']` value; if `window['_fs_host']` is `eu1.fullstory.com` pass `region="eu"`; if the host values are anything other than `fullstory.com`/`eu1.fullstory.com` standards, pass them through as `host`/`script` props.
3. `app/root.tsx` — add `<Subtext orgId="…" />` (plus `region`/`host`/`script` if derived above) inside `<head>` of the root layout. The component attaches Hydrogen's CSP nonce automatically via `useNonce()`.
4. `app/entry.server.tsx` — wrap the existing directives object: `createContentSecurityPolicy(withSubtextCSP({...existing directives}))`, importing `withSubtextCSP` from `@subtextdev/hydrogen` (pass `{region: 'eu'}` as its second argument for EU orgs). This replaces the manual CSP directive edits from Step 2 — do not also add the directives by hand.
5. `app/root.tsx` — add `<SubtextAnalytics />` anywhere inside `<Analytics.Provider>`. It forwards Hydrogen's commerce events (`product_viewed`, `cart_updated`, search, collection, add/remove-to-cart) into capture and starts/stops capture as Customer Privacy consent changes.
6. For Step 5 (identity), use the package's `useSubtextIdentity(customer && {uid: customer.id, displayName, email})` hook where the authenticated customer is available on the client (typically the account route), instead of a raw `FS('setIdentity')` call.
7. For Step 6 (analytics linkage), pass `onSessionUrl` to `<SubtextAnalytics>` instead of calling `FS('getSession')` directly — it fires with the session URL every time capture starts, which with consent gating can be well after page load: `<SubtextAnalytics onSessionUrl={(url) => { /* attach subtext_url to each detected tool here */ }} />`.
8. Order → session linkage (optional but recommended — ask the user, or include it in autonomous mode): pass `attachSessionToCart` to `<SubtextAnalytics>`. It writes the session URL onto the cart as a `_subtext_url` custom attribute, which Shopify carries through checkout onto the order — visible in the Shopify admin under "Additional details" on every order. This requires the app's cart route action to handle `CartForm.ACTIONS.AttributesUpdateInput`; if its switch lacks that case, add: `case CartForm.ACTIONS.AttributesUpdateInput: result = await cart.updateAttributes(inputs.attributes); break;`. If the cart route is not at `/cart`, pass `attachSessionToCart={{cartRoute: '…'}}`. Leakage note to relay to the user: order attributes can appear in customized order-notification email templates (default Shopify templates do not render them; the `_` prefix is the convention templates use to filter internal attributes). The URL is auth-gated either way. If the user cannot vouch for their notification templates, use `attachSessionToCart={{mode: 'ref'}}`, which writes an opaque session id (`_subtext_ref`) instead of a clickable URL.
9. Capture is consent-gated by default, matching how Shopify gates its own analytics. Tell the user: Shopify's privacy banner does not load on default `*.oxygen` preview URLs, so capture will not start there — verify on a real domain. Also note checkout hands off to Shopify-hosted pages, which this integration does not capture.
- Next.js (App Router) — Add to `app/layout.tsx` inside `<head>`, or as a `<Script>` component with `dangerouslySetInnerHTML`.
- Next.js (Pages Router) — Add to `pages/_document.tsx` inside `<Head>`.
- Remix — Add to `app/root.tsx` inside `<head>` of the root layout.
Expand Down