Skip to content

About

Strait web SDK (@straitlink/web): deferred deep links on your website, smart app banner and link-open analytics.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Strait

Strait SDK for the web

Straight to the screen. On the record.
A tap opens the exact screen, and every link open and install is recorded in your Strait dashboard.

Latest version SDK: Beta CI Licence: MIT

Docs · Platform status · Changelog · Talk to the Strait team

@straitlink/web

Deep linking for the web: count link opens on your site, join conversions to the tap, and show a smart app banner, in a few lines.

The device signature is kept in lockstep with the server and the other app SDKs via shared golden vectors (this package runs the same vectors in CI), so a change that would make them drift fails the tests.

Guided setup

A website needs no generated files, so there's no strait init step. The two steps below are the whole setup. Or let your AI coding tool do it: connect the Strait MCP server and run its get_started prompt with platform web; it pastes the exact setup from the docs.

Quick start (60 seconds)

1. Install.

npm install @straitlink/web

2. Report the open, on page load. The publishable key (st_pub_live_…) is in Dashboard → Get started and is safe in web pages.

import { reportWebOpen } from '@straitlink/web';

const open = await reportWebOpen({ publishableKey: 'st_pub_live_…', endpoint: 'https://<your-handle>.strait.link' });
console.log(open);

You should see: tap one of your Strait links that goes to this page. The page opens with ?strait_click=<tap id> in its URL, the console shows { reported: true, clickId: '…' }, and DevTools → Network shows one POST /v1/open answering 2xx. Opened without strait_click (typed URL), it shows { reported: false } and sends nothing.

Platform features

Feature Status Notes
Web links open the right page ● Live Handled by Strait; nothing to install.
Deferred match on first visit (resolveDeferredLink) Deprecated Not available on the web; removed in 0.9.0. See Deferred match: not on the web.
Link opens on your website (reportWebOpen) ◐ Beta Counts a page view as an open only when the URL carries strait_click (a landing from a Strait tap), joined to that tap. Needs the engine release that adds the tap id to web landings (on by default; turn it off per workspace or per link).
Smart app banner for mobile web (banner) ◐ Beta Styled with the Strait design system, light and dark. No requests of its own (apart from loading your icon), no cookies. Docs
iPhone install matching Opt-in Off until you choose it; proven on iPhone simulators, the real-iPhone run waits on our App Store listing. Runs in your app through the native SDKs, not in this package. Your choice in Dashboard → Settings → iPhone installs: device matching, paste handoff, both or neither, read from Strait at runtime. Device matching is off by default. iPhone matches are labelled Estimated until measured.
Published on npm ● Live npm install @straitlink/web

● Live · ◐ Beta · ○ Planned · – Not yet · Opt-in: off until you switch it on. The same words as the platform status page.

Install

npm install @straitlink/web

Use

A Strait link that goes to your website already opens the right page: Strait sends the visitor to the link's destination URL, so your site routes on that URL as it would for any visit. The SDK adds what the link alone can't: it counts the visit as an open of the tap, joins your conversions to that tap, and shows an "Open in app" banner on phones.

Count opens on your website

When Strait sends a tap to your website it adds the tap id to the URL (?strait_click=<tap id>, next to your own parameters such as UTMs). Call reportWebOpen on page load and that landing is recorded as a link open, joined to the tap, in your dashboard:

import { reportWebOpen } from '@straitlink/web';

const open = await reportWebOpen({ publishableKey: 'st_pub_live_…', endpoint: 'https://<your-handle>.strait.link' });
// open.clickId: the tap this visit came from; trackEvent attaches it for you

A visit without strait_click (typed URL, reload of a plain page, internal navigation) reports nothing. A reload or a shared copy of a landing URL is counted once (the open id comes from the tap id). It never throws. If your site rejects unknown query parameters, turn the tap id off for the workspace or for one link (webTapId: false on the link API).

Conversion events

Send a conversion (signup, purchase) and it shows up next to your app events, joined to the tap that brought the visitor, the same trackEvent as the iOS, Android, Flutter and React Native SDKs:

import { trackEvent } from '@straitlink/web';

const strait = { publishableKey: 'st_pub_live_…', endpoint: 'https://<your-handle>.strait.link' };
const ok = await trackEvent(strait, 'purchase', { value: 499, currency: 'INR', eventId: order.id });

The tap id comes from reportWebOpen (a landing with strait_click), kept in localStorage for 7 days; pass clickId to choose it yourself. eventId (your order id, 1-64 of A-Z a-z 0-9 _ . : -) makes a repeat count once. It resolves true when accepted and never throws. Input the engine would refuse (an empty name or one over 64 characters, a value outside 0-1,000,000,000, a currency that isn't 3 letters, a bad eventId, a linkId over 128 characters) is not sent: false and a console warning. Events sent from a web page can be faked by anyone with your publishable key; send revenue you rely on from your server.

Deferred match: not on the web

resolveDeferredLink is deprecated (0.8.3) and will be removed in 0.9.0. A deferred match needs device details that Strait saves only on the iPhone tap page (the Get the app step, for app installs), never for a tap that goes to a website, so a website could never get matched: true. It now sends no request and always returns { matched: false, matchMethod: 'none', reason: 'not_available_on_web' }, with one console warning per page. Calling it doesn't break your page.

What to use instead:

You wanted Use
The visitor lands on the page the link points to Nothing: the link already opens that URL. Route on it as usual.
Know which tap brought the visitor reportWebOpen on page load
Join a signup or purchase to that tap trackEvent: it attaches the tap reportWebOpen saw
Send phone visitors to your app The smart app banner
A deferred match after an app install The app SDKs (iOS, Android, React Native, Flutter, Capacitor) do this in your app

reportWebOpen sends your publishable key, the tap id from the URL and the page URL to /v1/open; trackEvent sends the event fields you pass to /v1/event. No device fields, no cookies, and the client never sees or sends an IP. /v1/open also carries this SDK's version (sdkVersion) so support can see which version a visit used; no app version is sent from the web.

User consent / opt-out

If your site asks for consent first (for example under India's DPDP Act or a GDPR consent flow in the EU), call setEnabled(false) until the visitor agrees: reportWebOpen and trackEvent then send nothing (the remembered tap id is deleted), and the choice is kept in localStorage across visits. setEnabled(true) turns it back on (default: on), and isEnabled() reads the switch. Whether you need consent, and for what, is a question for your own legal advice.

Smart app banner (mobile web)

Show an "Open in app" bar to visitors on phones. The button is a plain link to your Strait link, so the tap opens your app on the right screen, or the store with the destination kept through the install.

import { Strait } from '@straitlink/web';

Strait.banner({
  link: 'https://<your-handle>.strait.link/app', // a Strait link (opened as is)
  title: 'Hilltop Shoes',
  subtitle: 'Track your order in the app',
  icon: '/icons/app-192.png',
  theme: 'auto',                                  // 'light' | 'dark' | 'auto'
});

It shows only on phones and tablets, never inside your own app (pass inApp or appUserAgent), and stays hidden for 30 days after the visitor closes it (dismissDays). It makes no requests of its own (apart from loading your icon) and sets no cookies; closing it stores the time in localStorage. The only thing recorded is the tap on the link. dist/banner.js has no imports, so you can also copy it next to your pages and load it with <script type="module">.

How it looks

The banner follows the Strait design system (v5) in both themes: a warm white bar on light pages and a warm near-black bar (#191613) on dark ones, one orange button (#FF6A13 with ink text, 6.8:1), a 2 px focus ring, 44 px tap targets on touch screens and no motion when the visitor asks for reduced motion. theme: 'auto' follows the visitor's light / dark setting.

To match your own brand, pass accent (your button colour). The text on it is picked for contrast (ink or white) unless you pass accentText.

Preview every option locally: npm run build, serve the repo root, open examples/banner.html (add ?theme=dark, ?position=bottom or ?accent=%234A2C1D).

Light Dark
Smart app banner, light theme Smart app banner, dark theme

API

export purpose
reportWebOpen(config, opts?) on page load: records a landing from a Strait tap (strait_click in the URL) as an open; { reported, clickId? }
resolveDeferredLink(config, opts?) deprecated, not available on the web (sends nothing, matched: false); removed in 0.9.0. What to use instead
trackEvent(config, name, extra?) conversion / revenue event (value, currency, linkId, clickId, eventId); attaches the tap this visit came from; true when accepted
banner(options) / Strait.banner(options) smart app banner for mobile web; returns { element, dismiss, remove } or null when not shown
setEnabled(enabled) / isEnabled() opt-out switch for consent flows: off = nothing sent; kept in localStorage
computeSignature(inputs) the canonical signature (advanced/testing)
h32(s) the canonical hash (advanced/testing)

Size and speed

Measured 25 Oct 2026 on 0.6.3.

What Size or time How it was measured
npm package 12.5 KB download, 33 KB unpacked, no dependencies npm pack --dry-run
In your bundle, reportWebOpen only (Unreleased) 1.4 KB minified, 0.8 KB gzip same, measured on this branch
In your bundle, trackEvent only (Unreleased) 2.0 KB minified, 1.0 KB gzip same, measured 5 Nov 2026
In your bundle, banner only 5.1 KB minified, 2.6 KB gzip same
Everything 7.5 KB minified, 3.7 KB gzip (8.7 KB / 4.1 KB with reportWebOpen) same, whole entry
Start-up 1.5 ms to load the module, no set-up call fresh Node 26 process on an M-series Mac, median of 25

Example app

examples/web (Vite) routes on the deep link, reports the open and logs a purchase event, built against this repo's source (CI builds it on every PR). examples/banner.html previews the smart banner.

  1. npm ci here, then cd examples/web && npm ci.
  2. cp .env.example .env and set your publishable key (st_pub_…).
  3. npm run dev, then open http://localhost:5173/product/42.

Docs and support

About

Strait web SDK (@straitlink/web): deferred deep links on your website, smart app banner and link-open analytics.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages