CLItrail Docs

Handoff command

When the terminal cannot read the browser, the page can prepare an install command that carries an opaque token. Running that command reports the token after a successful install. No browser storage is read.

#When to use it

  • Safari, whose storage the hook does not read.
  • Windows: run the handoff command from WSL (a POSIX shell). PowerShell and cmd are not supported.
  • A visit on a phone or tablet, for an install on a computer.
  • A remote agent, SSH session, container or sudo environment that runs the command somewhere else.

#Prepare the command

Prepare before the visitor clicks Copy, then show and copy that same command:

const install = await InstallAttribution.prepareInstall({
  command: 'brew install your-org/your-cli',
  mode: 'auto',
  enabled: analyticsAllowed
});
document.querySelector('#install-command').textContent = install.command;
document.querySelector('#copy-install').onclick = () =>
  navigator.clipboard.writeText(install.command);

The SDK never touches the clipboard itself. Preparing ahead keeps the browser's requirement that clipboard writes happen during a click, and people who select the text by hand get the same command. If the SDK cannot load, keep showing your plain command.

OptionDefaultPurpose
commandrequiredYour install command, as trusted POSIX shell code, up to 65,536 characters.
modeautoauto, handoff or storage, below.
eventinstall_completedUse first_run for commands like npx your-cli, where a cached run is not a new install.
installationScopedefaultSeparates products on one website; 1 to 64 letters, digits, _ or -.
enabledtruefalse returns your command unchanged and issues no token.
attributionInstallAttribution.readyThe result of your own init call when you start the SDK yourself.
ModeBehaviour
autoPrepares a handoff when browser storage failed, and for Safari, Windows, Android, iOS, iPadOS, ChromeOS and browsers the hook does not read, including Chromium forks that name themselves (such as Opera and Yandex), whose profiles the hook does not search. Otherwise returns your command, which relies on the regular hook.
handoffAlways prepares a handoff. With the tag in its default storage mode, the handoff carries the tab's stored session source and Google's session attributes. Set data-mode="handoff" on the tag, or mode: 'handoff' in init, to skip the OPFS receipt and all web storage too; the handoff then carries only what the preparing page's URL and referrer show.
storageNever prepares a handoff.

auto is a routing hint, not a test of what the terminal can read. JavaScript cannot see a future container, sudo switch or remote run; choose handoff when those are common for your users.

#The result

prepareInstall resolves to { ok, mode, reason, command }, plus expiresAt for a handoff. Always display command.

modeMeaningTypical reason
handoffA wrapped command with a token.explicit_handoff, handoff_selected, safari_requires_handoff, platform_requires_handoff, unqualified_browser, opfs_unavailable
storageYour command; the hook will read the receipt.none
plainYour command, without attribution.disabled, initialize_first, invalid_configuration, handoff_unavailable, handoff_expired

#What the command does

The prepared command is sh -c '…' clitrail '<your command>' '<hook URL>' '<token>' '<scope>' '<event>', with every argument shell-quoted. When run, it:

  1. Runs your command with sh -c, with CLITRAIL_HANDOFF and CLITRAIL_INSTALLATION_SCOPE set, so a hook bundled in your installer reports the same token. Interactive aliases and functions are not available.
  2. Only if your command exits with 0, downloads your website's hook to a private temporary file and runs it with --handoff. A failed download is never executed, and the file is removed.
  3. Exits with your command's own status.

No analytics ID or secret ever appears in the command. Make sure your command returns a meaningful status: curl … | sh can succeed even when the download failed.

#Tokens

  • A token is 256 random bits; the service stores only its hash.
  • It expires with the visit it belongs to, 30 days by default. Reloading the page does not invalidate a command already prepared.
  • Each installation scope gets its own token, but every scope prepared on one page view refers to the same visit, so the page view counts once.
  • The first installation that reports it owns it. Retries and a later first run from that installation work; another installation cannot reuse it.
  • An invalid or expired token is recorded as unattributed. It never falls back to reconstruction.
  • On Free, the token is discarded unread, like every receipt: see No attribution on Free.

A token proves the command came from a prepared page. It does not prove who ran it, and anyone given the full command carries the same token.