🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@posthog/browser-common

Package Overview
Dependencies
Maintainers
22
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@posthog/browser-common

Internal shared browser utilities and extension primitives for PostHog Browser SDKs

latest
Source
npmnpm
Version
0.4.0
Version published
Weekly downloads
1.9M
134.34%
Maintainers
22
Weekly downloads
 
Created
Source

@posthog/browser-common

Internal shared browser utilities and extension primitives for PostHog JavaScript SDKs. This package is published so unbundled SDK outputs can resolve it at runtime, but it is not a public API surface and does not provide compatibility guarantees outside PostHog SDK packages.

The shared extension contract includes the interface an extension implements (Extension), the host adapter it receives (Client), and small shared runtime primitives such as Publisher.

This contract is designed so an extension can run unchanged across major versions of the web SDK. Concrete host adapters remain owned by their SDK packages; browser-v1 and browser-v2 composition and loading integration are separate from this shared runtime.

Concepts

Extension

What you implement. The host calls setup once and optional dispose for final cleanup:

import type { Disposable, Extension } from '@posthog/browser-common'

export function webContext(): Extension {
    let removeProperties: Disposable | undefined

    return {
        name: 'webContext',
        setup(client) {
            removeProperties = client.registerDynamicEventProperties(() => ({
                $current_url: window.location.href,
            }))
        },
        dispose() {
            removeProperties?.dispose()
        },
    }
}

setup(client) may be async to read state before the extension is ready. Async extensions must guard work after each await so cleanup cannot be followed by late listener or timer installation. dispose() is synchronous, optional, idempotent, and best-effort. Static app config goes in the constructor, not on Client.

Anything in setup that returns a Disposable must be held by the extension and disposed in dispose(). Use createDisposable(teardown) when adapting a synchronous callback into idempotent teardown.

Client

What an extension is given in setup — the adapter shared by extensions on that host SDK instance:

  • identity and session: distinctId, anonymousId, groups, session
  • events: capture(...), registerDynamicEventProperties(...), onEvent(...)
  • server config: onRemoteConfig(...)
  • transport: projectToken, sendRequest(path, init?)
  • storage and logging: kv, logger

Identity, session, and the public project token are always-ready synchronous reads. Operations that may perform I/O, including capture, sendRequest, and kv, are awaitable. onRemoteConfig immediately replays the latest known success or failure and then reports subsequent outcomes. Extensions that want a named log prefix can create a child with client.logger.createLogger('[myExtension]').

Host runtime

PostHog browser SDK implementations share extension registration and teardown through ExtensionRuntime, imported from the dedicated @posthog/browser-common/extension-runtime subpath. It reserves extension names during setup, rolls back failed setup, and disposes extensions once in reverse registration order without waiting for pending setup. Concrete SDKs still own their Client adapter and SDK lifecycle hooks.

ExtensionRuntime is host infrastructure, not part of the extension-author surface exported from the package root.

Publisher

Use Publisher<T> when an extension exposes an event stream. Keep the publisher private, expose only its listener, and dispose it with the extension:

import { Publisher, type Listener } from '@posthog/browser-common'

const changes = new Publisher<{ enabled: boolean }>()
export const onChange: Listener<{ enabled: boolean }> = changes.listener

changes.publish({ enabled: true })
changes.dispose()

Utilities

Reusable browser utilities are exposed through utils/* subpaths, but they are intentionally not re-exported from the package root or a utility barrel. Import the exact file needed so lazy extension bundles do not pull in unrelated helpers:

import { createLogger } from '@posthog/browser-common/utils/logger'
import { formDataToQuery } from '@posthog/browser-common/utils/request-utils'

Authoring

See the develop-extension skill (.agents/skills/develop-extension/SKILL.md) for the complete authoring and browser-v1 porting guide.

Status

Early and internal. The package currently defines the extension and client contracts, a shared host runtime, lifecycle helpers, and directly imported browser utilities under utils/* subpaths.

FAQs

Package last updated on 05 Aug 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts