本文へ移動
cccskills
無料GitHub で公開

posthog-adblock-bypass

Configure a Next.js app using posthog-js so session recording and dead-click capture survive browser ad blockers. Aliases the three blocker-flagged JS chunks (dead-clicks-autocapture.js, recorder.js, posthog-recorder.js) to bland same-origin paths via Next.js rewrites, and monkey-patches HTMLScriptElement so posthog-js requests the aliases. TRIGGER when posthog-js session replay or dead-click capture is failing in production with ERR_BLOCKED_BY_CLIENT or 404s on /static/dead-clicks-autocapture.js / /static/recorder.js / /static/posthog-recorder.js, or when the user wants to bypass ad blockers for these specific assets. Works alongside an existing PostHog reverse proxy (managed or otherwise) — only the three blocked files divert through Next.js, all other PostHog traffic stays on the original api_host. SKIP for unrelated PostHog setup, non-Next.js apps, or when capture/decide endpoints (/e/, /decide/, /array/*/config.js) are the ones being blocked — those need a different treatment.

インストール方法を見る

含まれるファイル(3)

  • SKILL.md9.6 KB
  • posthog-adblock-bypass.md11.6 KB
  • skills-lock.json275 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

PostHog ad-blocker bypass for Next.js

When to use this

The user has posthog-js working mostly — events, feature flags, decide, config all reach PostHog fine — but session recording and/or dead-click capture aren't working, and DevTools shows:

  • /static/dead-clicks-autocapture.js failing
  • /static/recorder.js or /static/posthog-recorder.js failing
  • ERR_BLOCKED_BY_CLIENT or a synthesized 404 (the file actually returns 200 via curl)

Root cause: ad blockers (uBlock Origin / Brave Shields / AdBlock Plus / EasyPrivacy) match on filename patterns (recorder, autocapture, dead-clicks) regardless of host. A reverse proxy alone doesn't help — renaming on a different host still trips the same filter. Confirmation step: ask the user to disable their ad blocker on the page; if the requests succeed, this skill applies.

This skill applies the surgical fix: only those three files divert through the Next.js app under bland filenames. All other PostHog traffic (events, decide, config, recording uploads) keeps using the existing api_host.

Prerequisites to confirm before implementing

  1. The project is Next.js (App Router or Pages Router both fine) with posthog-js from npm.
  2. Server-side: curl -I https://<api_host>/static/dead-clicks-autocapture.js?v=1.x returns 200. If it returns 404, the upstream proxy is misconfigured — fix that first, this skill won't help.
  3. Identify the PostHog cloud region: US (us-assets.i.posthog.com) or EU (eu-assets.i.posthog.com). Default to US if unclear, but ask.
  4. Locate the existing posthog.init(...) call (commonly src/lib/posthog.ts, a provider component, or app/layout.tsx). Note the file so you can hook the rewriter before init.
  5. Session replay must be enabled in the PostHog project dashboard (Settings → Project → Session replay → "Record user sessions"). If it's off, posthog-js never even tries to load the recorder, so this skill produces no visible effect. Surface this check to the user.

Implementation — three changes

1. Add rewrites to next.config.{ts,js,mjs}

Insert a rewrites() block. Use /_p/ as the alias prefix (or any path that doesn't contain words like recorder, analytics, tracking, posthog).

import type { NextConfig } from "next";

const PH_ASSETS = "https://us-assets.i.posthog.com"; // EU: "https://eu-assets.i.posthog.com"

const nextConfig: NextConfig = {
  // ...existing config...
  async rewrites() {
    return [
      { source: "/_p/dc.js", destination: `${PH_ASSETS}/static/dead-clicks-autocapture.js` },
      { source: "/_p/r.js",  destination: `${PH_ASSETS}/static/recorder.js` },
      { source: "/_p/r2.js", destination: `${PH_ASSETS}/static/posthog-recorder.js` },
    ];
  },
};

export default nextConfig;

Why all three: posthog-js renamed the recorder chunk across versions. Covering both recorder.js and posthog-recorder.js makes the skill version-resilient. Rewrites preserve the ?v=1.x.y query string automatically and incur no Node overhead.

If the project already has a rewrites() or redirects() block, merge rather than replace.

2. Create the script-tag rewriter

New file at src/lib/posthog-rewrite-loader.ts (adjust path to match the repo's lib convention):

const REWRITES: Array<[RegExp, string]> = [
  [/\/static\/dead-clicks-autocapture\.js/, "/_p/dc.js"],
  [/\/static\/posthog-recorder\.js/,        "/_p/r2.js"],
  [/\/static\/recorder\.js/,                "/_p/r.js"],
];

export function installPostHogScriptRewriter() {
  if (typeof window === "undefined") return;
  const w = window as Window & { __phRewriteInstalled?: boolean };
  if (w.__phRewriteInstalled) return;
  w.__phRewriteInstalled = true;

  const desc = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, "src");
  if (!desc?.set || !desc?.get) return;

  Object.defineProperty(HTMLScriptElement.prototype, "src", {
    configurable: true,
    enumerable: true,
    get() {
      return desc.get!.call(this);
    },
    set(value: string) {
      if (typeof value === "string") {
        for (const [pattern, replacement] of REWRITES) {
          if (pattern.test(value)) {
            const qIndex = value.indexOf("?");
            const query = qIndex >= 0 ? value.slice(qIndex) : "";
            value = replacement + query; // strip host -> same-origin
            break;
          }
        }
      }
      desc.set!.call(this, value);
    },
  });
}

Notes:

  • The __phRewriteInstalled flag is required because Next.js dev HMR can re-execute modules and Object.defineProperty would otherwise throw.
  • Stripping the host (replacing the entire URL with /_p/dc.js?v=...) makes the request same-origin, avoiding a CORS preflight on top of the blocker bypass.
  • The patcher targets the src property setter on the prototype — posthog-js loads chunks by setting script.src, so this catches them. It does not catch fetch() or dynamic import() (not used by posthog-js for these chunks today, but worth noting if a future SDK version changes).

3. Wire the rewriter to run before posthog.init

The patcher must be installed before any posthog.init call. Module-level code in the same file as posthog.init works because module evaluation precedes useEffect:

// src/lib/posthog.ts (or wherever posthog.init lives)
import posthog from "posthog-js";
import { installPostHogScriptRewriter } from "@/lib/posthog-rewrite-loader";

if (typeof window !== "undefined") {
  installPostHogScriptRewriter();
}

export const initPostHog = () => {
  if (typeof window !== "undefined") {
    posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
      api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, // unchanged
      // ...existing config...
    });
  }
};

export { posthog };

If posthog.init is called from <Script strategy="beforeInteractive"> in app/layout.tsx instead of from a client module, put the patcher in its own <Script strategy="beforeInteractive"> block placed above the PostHog one. Don't use afterInteractive — by then posthog may have already started loading chunks.

Verification

  1. Server side — after deploy:

    curl -I "https://<your-domain>/_p/dc.js?v=1.0"
    curl -I "https://<your-domain>/_p/r2.js?v=1.0"
    

    Both should return 200, content-type: text/javascript. If 404, the rewrite isn't picked up — Next.js needs a rebuild after next.config changes.

  2. Browser with ad blocker enabled — in DevTools Network:

    • Requests to /_p/dc.js and /_p/r2.js succeed (200).
    • No /static/dead-clicks-autocapture.js or /static/posthog-recorder.js requests visible.
    • In uBlock Origin's Logger, /_p/* entries should show -- (allowed), not red.
  3. PostHog dashboard:

    • Live Events shows dead-click events firing.
    • Session replay shows recordings (allow ~5 min for ingestion).
    • If recordings still don't appear, the issue is likely the dashboard toggle (Settings → Session replay), not this skill.

Common follow-ups and pitfalls

  • "It still doesn't work after deploy" — rewrites only take effect after next build. Local dev needs npm run dev restart. Production needs a redeploy.
  • "A different chunk is now blocked" — surveys, web-vitals, exception-autocapture. Add a fourth rewrite + a fourth regex entry. Pattern is identical.
  • "Capture endpoints are also blocked" — /e/, /decide/, /array/*/config.js getting blocked is a different problem (host-level rather than filename-level). Solve with a PostHog reverse proxy on the user's own domain, not this skill. PostHog's docs cover that.
  • "Want to proxy everything through Next.js instead" — possible but discouraged. Session recording is high-volume (kilobytes per second per active user); routing through Next.js multiplies function invocations 10–100×. The PostHog-managed proxy is purpose-built for this load. Use full-proxy only if you have a hard CSP/compliance requirement.
  • SDK upgrades — if posthog-js renames a chunk in a future version, the rewriter silently misses it. After upgrades, watch DevTools Network for any /static/*.js request leaking through and add a regex entry.
  • Network-level blockers (Pi-hole / NextDNS) blocking by domain are not bypassed by this. They're a much smaller cohort than browser extensions and your own domain isn't on their lists.

Files modified summary (template for the PR description)

FileChange
next.config.{ts,js}Add rewrites() for /_p/dc.js, /_p/r.js, /_p/r2.js
src/lib/posthog-rewrite-loader.tsNew — patches HTMLScriptElement.prototype.src
src/lib/posthog.ts (or equivalent)Call installPostHogScriptRewriter() at module load

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Analyze tau2-bench task export files to identify exactly where and why tasks failed. Map failures to specific conversation rounds, show root causes, check whether relevant documentation was available, and cite sources. Use this skill whenever you need to debug a tau2-bench evaluation, understand why an agent made wrong decisions, identify missing knowledge, or review task performance—especially when context length, eligibility criteria, or policy compliance might be at fault.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

How to develop, modify, and extend the Claude Code codebase following its established programming style, patterns, and conventions. Use this skill whenever working on the claude-code source — adding tools, commands, utils, components, types, hooks, services, or fixing bugs. Also use when the user asks about claude-code architecture, coding standards, file organization, or wants to understand how the codebase works. This skill ensures all contributions match the existing codebase style exactly.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

Generate a complete, beginner-friendly explanation of an entire code repository as a set of markdown files. Maps the repo structure with `treecap` (installing it if missing), studies the actual source, then writes a `CODE_EXPLANATION/` folder containing an `OVERVIEW.md` plus numbered deep-dive files (01_architecture.md, 02_models.md, ...) that explain how the code is built, what it does, and how the pieces fit together — illustrated with real code excerpts. Use this skill whenever the user wants to understand, document, onboard onto, or get a walkthrough of a codebase: phrases like "explain this repo", "explain the code", "code explanation", "walk me through this codebase", "help me understand how this is built", "document the architecture", or "what does this project do" — even if they don't say the word "skill". Prefer this over ad-hoc summaries whenever the goal is a durable, written explanation of a whole repo.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

Run inference on Fireworks AI — direct, through the Leanmcp AI Gateway proxy (aigateway.leanmcp.com) for observability, or via LiteLLM / the OpenAI SDK / raw HTTP. Covers the endpoint-and-key matrix for each route, serverless vs dedicated deployments and their cold starts, browsing and filtering the model catalogue, reasoning models that return content:null with the answer in reasoning_content, function calling, concurrency and load testing, and runner scripts where many models share one protocol with a --use-proxy toggle. Use this skill whenever the user mentions Fireworks, FIREWORKS_API_KEY, api.fireworks.ai, fireworks_ai/ model ids, accounts/fireworks/models/..., a Fireworks deployment id, the Leanmcp gateway or LEANMCP_API_KEY, app.leanmcp.com observability, or gpt-oss / kimi / glm / qwen / deepseek served on Fireworks; wants to route LLM calls through a proxy for logging or cost tracking; is debugging empty responses, 404s, scope errors, cold starts, or "the gateway isn't working"; wants to pick a Fireworks model with tool calling; or wants to sweep several models over one benchmark. Reach for it even on vague asks like "why is this model returning nothing" or "set up inference for these models" when Fireworks is in play.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

Build, run, debug and ship 3D city games in Godot 4 — procedurally generated cities (block grids, districts, weighted building typologies, MultiMesh batching, facade shaders, terrain, day/night, landmarks), first-person controllers, headless verification, Blender-generated .glb assets, rigged character and animation packs, real OpenStreetMap-derived cities, WebAssembly export, and cloud GPU streaming on GCP. Use this skill whenever the work involves Godot or a .gd/.tscn/.gdshader/project.godot file; whenever someone wants to start, set up, clone onto a new machine, or stand up a 3D game or city generator; whenever they mention procedural city, city generator, block grid, building typology, MultiMesh, facade shader, terrain heightmap, navmesh, Godot export templates, export presets, headless Godot, .glb pipeline, Blender asset generation, character rigs or borrowed animations; and whenever they want to deploy or share a game — web export, SharedArrayBuffer/COOP/COEP, Selkies, pixel streaming, GPU VM, or "let people play this without installing anything." Reach for it even on vague asks like "get this running", "why is my city slow", "my model faces backwards", "make it work on a cloud machine", or "set this up somewhere else too" when a Godot 3D project is in play.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

Scaffold a native iOS app (SwiftUI, no dependencies) from nothing, run it in the Simulator, and archive + upload it to TestFlight entirely from the command line. Bundles working scripts for icon generation, simulator run, and signed upload via the App Store Connect API. Use this whenever the user wants to build, run, ship, or debug an iOS/iPhone/iPad app, mentions Xcode, SwiftUI, .xcodeproj, xcodebuild, simctl, provisioning, code signing, App Store Connect, TestFlight, archiving, or "get this on my phone" — and also when an existing iOS build is failing on icons, signing, teams, destinations, or duplicate build numbers.

日本語の概要は準備中です。原文の説明を表示しています。

Leanmcp/gateway-skills2,1112026年10月8日 更新

Leanmcp のスキルをすべて見る

このスキルの問題を報告する