Drop-in script
sh.js for sites without a build step: pageviews and events with data-property, redirect experiments, splithub.track and identify.
For sites without a build step (static HTML, Webflow, Framer, Shopify themes, WordPress, landing-page builders) SplitHub Cloud serves a small script that collects analytics, runs redirect experiments and tracks goals from the hosted config.
<script src="https://go.splithub.io/sh.js" data-key="pk_live_…" data-property="sh-x1h78w"></script>
Put it in <head>, as early as possible. The public key is safe to publish: it can only send events and read the public config.
What it does on every page
- Reads the hosted config and live overrides (cached in
localStorage, refreshed on load when older than 60 s). - For
redirectexperiments whosematchfits the current path: assigns the visitor with the same hash as the SDK (targeting flows included) and, when the variant points elsewhere, navigates to that destination. The rendering hold below reduces flashes. - Records the exposure, fires
pageviewgoals, bindsclickgoals from their selectors, and exposeswindow.splithub.track()andwindow.splithub.identify(). - With
data-property: records a pageview for the analytics property, and another on every client-side navigation.
<button onclick="splithub.track('signup')">Start</button>
<script>
(window.splithubq = window.splithubq || []).push(['track', 'purchase', { revenue: 49 }]);
</script>
Analytics
data-property names the property that receives pageviews and events; without it the script sends no analytics. Find the id on the property's page in the dashboard, or with npx splithub analytics.
- Pageviews: one per page load and one per client-side navigation (history and hash routes), with time on page and scroll depth. Single-page sites need nothing extra.
- Events:
splithub.track(name, props), any name of letters, digits, spaces and_ . : / -up to 64 characters, props a flat object up to 4 KB. The same call converts every experiment whose goal it is. - Users:
splithub.identify(userId, traits)after sign-in,splithub.identify(null)on sign-out. Use your internal id, never an email.
<script>
window.splithubq = window.splithubq || [];
splithubq.push(['track', 'Video Played', { id: 3 }]);
splithubq.push(['identify', 'user_42', { plan: 'pro' }]);
</script>
window.splithub exists as soon as the script tag runs, so inline handlers can call it before the config arrives; calls made before the script loads go through the splithubq queue. Keep one install per property: if the SDK also runs on the page for the same property, the first to send a page collects pageviews and the other sends only its own track() calls.
Hold rendering during the decision
On a page that is the subject of a redirect experiment, name it so the script holds rendering until the decision is made, even on the first visit with an empty cache:
<meta name="splithub-experiment" content="landing">
The script also holds rendering when there is no cached config or a cached redirect matches the page. The meta tag explicitly requests a decision for this page. The hold lasts up to 1,500 ms by default; a timeout can reveal the original page. Put the meta tag before the script.
What it cannot do
component and value experiments need the SDK in the app: the script does not change your markup. Use the script for analytics, whole-page tests and goal tracking, the SDK for everything inside the page.
Options
| Attribute | Default | Meaning |
|---|---|---|
data-key |
required | the project's public key |
data-property |
none | the analytics property id (sh-…); without it no pageviews or events are sent |
data-endpoint |
script origin + /v1/events |
full events URL for a self-hosted cloud or staging |
data-hold |
1500 |
maximum rendering hold in ms; off disables the hold |
Use ?sh_debug=1 in the page URL for console diagnostics.
Where experiments come from
Create redirect experiments in the dashboard (New experiment → Redirect) or in splithub.config.ts and push. Targeting flows (country, device, UTM…) created in the dashboard are evaluated by the script with the visitor's geo from the edge.