
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@posthog/browser-common
Advanced tools
Internal shared browser utilities and extension primitives for PostHog Browser SDKs
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 capabilities it is handed (Client), and small shared
runtime primitives such as Publisher.
An extension written against this contract runs unchanged across major versions of the web SDK:
Each SDK provides a client adapter that implements Client over its own
internals, so extension code never depends on a specific SDK.
ExtensionWhat you implement. The host calls only setup and dispose:
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 (read async state before you're ready); dispose()
may be async (final flush). Static config the app sets goes in your constructor,
not on the Client.
Anything in setup that returns a Disposable must be held by the extension
and disposed in dispose().
ClientWhat an extension is given in setup — the host's capability surface:
distinctId, anonymousId, groups, sessioncapture(...), registerDynamicEventProperties(...) (contribute properties), onEvent(...) (observe)apiRequest(path, init?)getRemoteConfig() (current), onRemoteConfig(...) (changes)onNewSession(...)getExtension(token)kv, loggerSynchronous members are always-ready in-memory reads; everything that does I/O
or waits for readiness (capture, apiRequest, kv, getRemoteConfig) is
asynchronous.
PublisherUse Publisher<T> when an extension provides its own event stream to other
extensions or to app-facing controls. Keep the publisher private, expose only its
listener, and dispose it when the extension is torn down:
import { Publisher, type Listener } from '@posthog/browser-common'
const changes = new Publisher<FeatureFlagsChange>()
export const onChange: Listener<FeatureFlagsChange> = changes.listener
changes.publish({ flag: 'beta-ui', value: true })
changes.dispose()
Extensions depend on one another through tokens, never implementation imports:
import { FeatureFlags } from './feature-flags/token'
const flags = client.getExtension(FeatureFlags) // FeatureFlagsExtension | undefined
if (flags && (await flags.getFeatureFlag('beta-ui'))) {
/* … */
}
A token is an implementation-free branded string, so importing it never pulls
the provider's code into your bundle — each extension stays independently
tree-shakable and lazily loadable. Use a package-qualified runtime string, such
as posthog.featureFlags, that is globally unique and stable so separately
compiled scripts resolve the same capability. An extension that provides a
capability declares its token(s) in provides.
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 you need 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'
See the develop-extension skill
(.agents/skills/develop-extension/SKILL.md)
for the full guide: the capability cheatsheet, the rules (enrichers are
synchronous, dispose your disposables, design for asynchronous readiness,
cross-extension state goes through getExtension, not shared storage), and the
v1 → Client porting map.
Early and internal. The package currently defines the extension contract, the
shared Publisher helper, and directly imported browser utilities under
utils/* subpaths. Additional shared runtime helpers — key-value stores, the
registry implementation, and a test Client — will land alongside the first
ported extension.
FAQs
Internal shared browser utilities and extension primitives for PostHog Browser SDKs
The npm package @posthog/browser-common receives a total of 1,636,055 weekly downloads. As such, @posthog/browser-common popularity was classified as popular.
We found that @posthog/browser-common demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 22 open source maintainers collaborating on the project.
Did you know?

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.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.