Securely install the JavaScript SDK

Contents

The JavaScript SDK runs with the same access to your page as your own application code. Use version controls, Subresource Integrity (SRI), Content Security Policy (CSP), and nonces to control how you load it. These controls protect different boundaries; none makes untrusted code safe to run.

Pin and update SDK versions

If you need to review SDK changes before deployment, follow snippet versioning for CDN installations or the package-manager lockfile guidance for npm installations. Use an exact dependency version, commit the lockfile, and enforce frozen installs in CI.

Version pins and versioned feature scripts select releases; they don't verify the bytes returned by a CDN or proxy. The token-specific /array/<token>/config.js script isn't pinned by strict_script_versioning.

Review and deploy updates regularly so pins don't prevent security fixes from reaching your users. See keeping SDKs current.

Use Subresource Integrity with a pinned script

Subresource Integrity (SRI) enables the browser to check a downloaded script against an expected cryptographic hash before executing it. Use it with an exact-version URL, not a moving URL such as /static/array.js or /static/1/array.js.

Download and review the integrity manifest

Release integrity manifests and the loader's data-core-integrity attribute require posthog-js 1.445.0 or later. Use the release manifest's SHA-384 hashes instead of calculating them manually.

Download the manifest during your dependency approval or deployment process. Replace <SDK_VERSION> in all examples with the same exact release you have reviewed.

Terminal
curl --fail --show-error --silent --location \
"https://us-assets.i.posthog.com/static/<SDK_VERSION>/integrity.json" \
--output posthog-integrity.json

The manifest's files object maps asset filenames to complete SRI values, such as "array.js": "sha384-...". Use files["array.js"] for the core SDK and files["loader.js"] for the static loader. The npm package also includes its build's manifest at dist/integrity.json.

Use the CDN manifest from the regional asset host you serve; regional toolbar assets can differ. If you use a reverse proxy, it must serve the same approved bytes. Review the release and assets through your normal dependency approval process, then store the selected hashes in your application source or build artifacts.

A manifest from a compromised server doesn't establish that the code is trustworthy. Don't fetch expected hashes dynamically at page load.

Add the hashes to the SDK loader

Use this loader instead of the inline snippet. Set integrity to files["loader.js"] and data-core-integrity to files["array.js"] from your approved manifest:

HTML
<script
src="https://us-assets.i.posthog.com/static/<SDK_VERSION>/loader.js"
integrity="sha384-<LOADER_SHA384_BASE64_DIGEST>"
data-core-integrity="sha384-<ARRAY_SHA384_BASE64_DIGEST>"
data-project-token="<ph_project_token>"
crossorigin="anonymous"
></script>

If you serve the loader through a reverse proxy, set data-api-host to your ingestion URL. Move existing initialization options into data-config as JSON. For function-valued options, set data-defer-init="true" and call posthog.init(...) explicitly.

Replace both complete hash placeholders and the project token. When upgrading, update the version and both hashes together. If a hash doesn't match, the browser blocks execution; don't retry without integrity.

Cross-origin SRI requires CORS response headers. PostHog's asset hosts provide these; preserve them if you use a cross-origin proxy.

Understand the coverage

These hashes protect only loader.js and array.js, not additional scripts such as the recorder, surveys, toolbar, or config.js. For controls on optional SDK scripts, see the prepare_external_dependency_script hook. To avoid runtime executable downloads altogether, bundle the SDK without external scripts.

Configure Content Security Policy

CSP limits which resources the browser can load and which scripts it can execute. Follow the CSP directives guide for SDK scripts, API connections, workers, and optional toolbar resources.

Keep script-src and connect-src separate in your review: permitting event ingestion doesn't require permitting remote JavaScript. Bundling the SDK doesn't remove the need to permit its API requests. Test the features you enable before enforcing your policy, and use browser console reports to find blocked resources rather than broadly adding unsafe-inline or unsafe-eval.

Use CSP tracking to test your policy in report-only mode before enforcement and monitor violations after deployment.

A reverse proxy changes where requests go. It doesn't verify script contents or reduce the privileges of code running on your page.

Use nonces for authorized scripts and styles

Follow supporting nonce directives for SDK configuration. Generate an unpredictable nonce for each HTML response, and authorize the initial installation code as well as SDK-created elements.

Nonces authorize execution; they don't verify script contents or replace SRI.

Bundle the SDK without external scripts

To avoid runtime executable downloads, install the SDK from npm with a package manager and follow bundling extensions for the no-external import options and feature trade-offs. Installing from npm with the default posthog-js import doesn't prevent dependency downloads.

Set disable_external_dependency_loading: true at the first initialization of every SDK instance. This blocks the standard SDK script loader, including executable config.js. Without preloaded configuration, the SDK requests project configuration as JSON instead. Configuration, flags, and events still use the network. See the SDK configuration reference for available controls.

Don't combine this setup with the snippet, tag-manager installations, or another permissively configured SDK copy. No-external builds don't remove a shared loader or renderer already registered by another bundle.

Preventing script downloads doesn't sanitize remote HTML or disable bundled renderers. Review remotely configured UI separately. This setup doesn't isolate the SDK from your page or protect against a compromised package or build pipeline.

Review data access and verify your installation

Use only your public project token in browser code, never a personal API key. Client-side feature flags aren't authorization checks; enforce access control on your server.

Review data collection and consent and session replay masking separately. Capture opt-out settings aren't a guarantee of no network requests or script downloads.

Before deployment and after each upgrade:

  • Use a clean browser profile to check the Network panel during initialization, event capture, feature flag evaluation, and optional features.
  • Check for duplicate SDK installations, unexpected executable downloads, CSP violations, and integrity failures.
  • For the no-external setup, verify that JSON configuration, flags, and events work without vendor script downloads. Test without CSP first, then with CSP, so blocked requests don't hide unwanted loading attempts.
  • For SRI, test that an incorrect hash blocks execution and that the correct hash loads the SDK. Check any proxy or CDN transformations that could change the bytes.

Still have questions?

Was this page useful?