Remote Settings
On boot, AnalyticsBrowser.load fetches the CDN settings JSON for your
writeKey ({cdnURL}/v1/projects/{writeKey}/settings) itself, hands it to
analytics-next (which then skips its own fetch — the request count is
unchanged), and reads a custom silo block out of it:
{ "integrations": { "...": "standard Segment fields" }, "silo": { "timeOnPage": { "enabled": true, "idleSeconds": 60 }, "consent": { "mode": "opt-out" }, "ubid": { "mode": "opt-in" }, "debug": { "enabled": false } }}Because the settings are served per writeKey from the Silo CDN, features can be toggled and tuned from the web, without a redeploy of the consuming site.
Precedence
Section titled “Precedence”Plugin defaults < code config < remote settings. Remote values win — the point is post-deploy control. The block is partial: fields it omits fall through to whatever the site’s code config (or the library default) says.
If the settings fetch fails — network error, non-2xx, malformed body — the
library loads with pure code config and lets analytics-next fetch the
settings itself. Remote unreachable behaves exactly like a library without
remote settings.
silo.timeOnPage
Section titled “silo.timeOnPage”| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Kill switch — false skips plugin registration entirely (no listeners, no middleware, no beacons). |
minSeconds | number | — | Minimum seconds before sending an event. |
maxSeconds | number | — | Maximum seconds to cap the event at. |
idleSeconds | number | — | Seconds of zero user input after which the engagement counter pauses. 0 disables idle gating entirely. |
heartbeatSchedule | number[] | false | — | Bounded-exponential heartbeat schedule in seconds. false disables heartbeats entirely. |
scrollTracking | boolean | — | Document-relative scroll-depth tracking. |
A — default means the field falls through to the site’s code config
when absent — see Configuration for the library defaults.
Only enabled has a remote-level default, because it controls library
behavior no code config can express.
enabled: false skips plugin registration entirely: no listeners, no
middleware, no beacons. apiHost, writeKey, and eventName are
deliberately not remote-tunable (endpoint redirection attack surface /
downstream data-contract changes).
silo.consent
Section titled “silo.consent”| Option | Type | Default | Description |
|---|---|---|---|
mode | ConsentMode | "opt-out" | Per-writeKey consent regime — the do-nothing default applied when the visitor has expressed no choice. "opt-out": silo collects by default (US / no consent regime). "opt-in": silo collects nothing until consent (GDPR/ePrivacy/Law 25). The code-config offlineFallbackMode is the fallback when the CDN settings are unreachable. |
mode sets the per-writeKey do-nothing default for silo’s own collection —
flipping a property’s regime from the web is a single edit here, no redeploy.
What opt-in/opt-out mean, how GPC and the visitor’s live CMP choice take
precedence, and the offlineFallbackMode fallback are all documented in
Consent — the single source for consent behavior.
silo.ubid
Section titled “silo.ubid”| Option | Type | Default | Description |
|---|---|---|---|
mode | ConsentMode | "opt-in" | Per-writeKey consent regime for ubid. Default ("opt-in") lives in SILO_REMOTE_DEFAULTS (defaults.ts): a browser fingerprint is profiling tech, so it collects nothing until consent. Set "opt-out" per writeKey to collect ubid by default (US / no-consent-regime properties). This is the only knob that flips it, and is deliberately remote-only — opting ubid OUT of consent is a deliberate act, never a CDN-unreachable fallback. |
ubid (universal browser id) is its own consent capability with its own regime,
overridable per writeKey here. Unlike consent.mode, ubid defaults to
opt-in: a browser fingerprint is profiling tech, so it collects nothing
until the visitor consents — independent of the property’s consent.mode. Set
"opt-out" for a writeKey to collect ubid by default (US / no-consent-regime
properties). This is the only way to flip it, and is deliberately remote-only
— there is no code-config fallback, so opting ubid out of consent is always a
deliberate per-writeKey act, never a CDN-unreachable default. GPC still denies
ubid regardless. See Consent for how the gate resolves.
silo.debug
Section titled “silo.debug”| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Master debug switch. true stamps context.silo.debug on every event (so the gateway allows this writeKey’s localhost traffic) and enables verbose client-side logging. |
Debug mode is a per-writeKey developer switch. It resolves like every other
setting (remote > code config > default false), but its effect reaches
past the browser: when on, the library stamps context.silo.debug on every
event, and the event gateway uses that stamp to decide whether to accept
localhost traffic.
By default the gateway drops events sent from localhost / 127.0.0.1 —
local development is test noise, not real analytics data, so it never reaches
your event store or the debugger. Turning debug on (here, or with debug: true
in the site’s AnalyticsBrowser.load config) makes the gateway let that
writeKey’s localhost events through so you can watch them land while developing.
Flip it back off — or just leave it off in production — and localhost stops
reaching the pipeline again.
TypeScript contract
Section titled “TypeScript contract”The block’s shape is exported as SiloRemoteSettings /
SiloRemoteTimeOnPage / SiloRemoteConsent / SiloRemoteUbid /
SiloRemoteDebug — import them into whatever serves or edits the settings JSON
so both ends of the contract compile against one type:
import type { SiloRemoteSettings } from "@adpharm/silo-analytics";The defaults shown in the tables above (the time-on-page enabled kill switch
and the per-capability consent modes) are also exported as a runtime const, so
an editor can render the effective default without hardcoding it:
import { SILO_REMOTE_DEFAULTS } from "@adpharm/silo-analytics";The enabled kill switch is mirrored by the library’s branch logic; the
consent/ubid modes are read at runtime as the final fallback. The editor
and these docs read this const so the default shown is always the one the
contract ships.