Gate manual PostHog ping when opted out

PostHog's `cookieless_mode` keeps `is_capturing()` returning `true`
after rejection: in `"always"` mode `opt_out_capturing()` is a no-op
that just warns, and in `"on_reject"` mode it actually registers a
cookieless distinct_id and re-fires a pageview rather than stopping
captures. The example panel's "Capture test event" button therefore
still shipped events (cookielessly) for visitors who had rejected
consent, contradicting the "only delivered when opted in" hint.

Disable the button whenever the cached status reports opted out, and
keep a defensive `has_opted_out_capturing()` check in the click
handler so the example fails closed if the panel is reused without
its disabled-state wiring. Drop the now-redundant disclaimer next to
the last-sent timestamp.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-05-27 14:31:52 +02:00
parent a447c62e19
commit 448b5a043e
2 changed files with 11 additions and 2 deletions

View File

@@ -55,6 +55,15 @@ export function ThemedBannerTab({ events, pushEvent }: ThemedBannerTabProps) {
);
const sendPing = useCallback(() => {
// Defensive: `PosthogPanel` already disables the button while opted out,
// and pure telemetry pings like this one are fine to ship cookielessly
// (PostHog's `cookieless_mode` is designed exactly for that). Only gate
// manual captures when the event carries user-specific data — e.g. an
// identified `distinct_id`, an email, a workspace name — that must not
// leave the browser without consent. We keep the guard here purely to
// make the example fail closed if the panel is reused without its
// disabled-state wiring.
if (posthog.has_opted_out_capturing()) return;
posthog.capture("themed_tab_manual_ping", { source: "example" });
setManualPing(new Date().toISOString());
}, []);

View File

@@ -58,14 +58,14 @@ export function PosthogPanel({ status, manualPing, onSendPing }: PosthogPanelPro
</table>
<button
onClick={onSendPing}
disabled={!status.initialized}
disabled={!status.initialized || status.optedOut}
style={{ padding: "6px 12px", fontSize: 13 }}
>
Capture test event
</button>
{manualPing && (
<span style={{ marginLeft: 12, color: "#666", fontSize: 13 }}>
last sent: {manualPing} (only delivered when opted in)
last sent: {manualPing}
</span>
)}
</div>