porcupine Documentation GitHub ↗
Porcupine v0.10.0 View Markdown ↗

PostHog SDK compatibility#

The v0.10.0 test matrix pins posthog-js 1.447.3 and posthog-node 5.63.1. Porcupine accepts event capture from these SDKs. Its query, management and MCP interfaces use Porcupine’s own contracts. Tested behaviors and known gaps

Configure browser capture#

Install posthog-js@1.447.3 in your application. Create a mixed project and use its public ingestion key in the browser. Add the application’s exact origin to PORCUPINE_ALLOWED_ORIGINS on the server. Copy the profile definitions into your application and choose the mode you need.

import posthog from 'posthog-js'
import { cookielessProfile } from './profiles.mjs'

posthog.init(projectIngestionKey, {
  ...cookielessProfile,
  api_host: porcupineOrigin,
  opt_out_useragent_filter: false
})
posthog.capture('article_opened', { section: 'news' })

Set porcupineOrigin to your instance origin, for example https://analytics.example.com. The cookieless profile disables autocapture and browser storage. Porcupine derives a project-specific daily pseudonym when the SDK sends the cookieless sentinel. To link a returning browser at login, choose identifiedBrowserProfile and call posthog.identify(). For backend events, use the Node profile or the native ingestion endpoint. Identity and privacy

Configure backend capture#

For a mixed project, install posthog-node@5.63.1 and copy the same profile definitions into your application. Set PORCUPINE_URL to the instance origin and PORCUPINE_WRITE_KEY to the project's public ingestion key.

import { PostHog } from 'posthog-node'
import { nodeProfile } from './profiles.mjs'

const analytics = new PostHog(process.env.PORCUPINE_WRITE_KEY, {
  ...nodeProfile,
  host: process.env.PORCUPINE_URL
})
analytics.capture({ distinctId: 'user-7', event: 'article_published' })
await analytics.flush()
await analytics.shutdown()

For a backend using private service credentials or a server_only project, use the native ingestion endpoint.

Cookieless product default#

The supported cookieless profile is exported as cookielessProfile in compat/profiles.mjs. The default keeps anonymous capture free of browser storage. To link activity at login, use the opt-in identified profile with person_profiles: "identified_only"; it requires persistent IDs.

browser.cookieless-no-storage runs the real SDK in isolated Chromium contexts. It verifies successful CORS responses and stored daily pseudonyms for repeated events, reload, fresh same-UA context, different UA and a separate project. It also checks empty cookies/localStorage/sessionStorage and removed IP/correlation fields. Deterministic Go tests cover next-day rotation, restart stability, midnight transaction ordering, clock rollback, trusted proxies and atomic failure. See the identity design.

Test coverage and limitations#

The matrix covers Node retry deduplication, a browser batch with gzip, persistent-ID and reset behavior, cookie-free browser capture, and identified capture. Browser retry behavior, independent new-tab sessions, and beacon and XHR transports remain outside the tested contract. Autocapture, feature flags, replay, surveys, group updates and general aliasing are outside the supported profile. Review the compatibility matrix before changing your SDK configuration.

For fixture provenance, test commands, and SDK upgrade checks, see SDK compatibility tests.