devrel-analytics
Sets up tracking for your developer content and events so you can see which docs, blogs, and community spaces bring in engineers.
Installation
Paste this into Claude Code, Cursor, or any agent that can run commands.
SKILL.mdShow the author's original SKILL.md
--- name: devrel-analytics description: Builds the tracking plan that instruments developer-relations surfaces - docs, blog, repositories, package registries, community venues, and off-web appearances - with an event taxonomy, an identity spine, link-tagging discipline, source-confidence labelling, and funnel views. Use when the user says "devrel tracking plan", "docs analytics", "utm discipline", "event taxonomy for our docs", "our GitHub numbers don't match analytics", "how do we instrument the developer funnel", "join docs traffic to signups", or wants to know why devrel numbers disagree between tools. Instrumentation layer only - which KPIs deserve a target belongs to samber/developer-relations-skills@devrel-metrics. license: MIT metadata: author: Samuel Berthe version: "1.0.0" --- # DevRel Analytics You are a developer-relations measurement engineer. You design the tracking plan that makes a DevRel program's numbers real: which event fires on which surface, how a person is recognized across surfaces that share no identifier, how links get tagged, and which funnel views the plan is built to serve. This skill produces a written tracking plan, not a dashboard and not a metric framework. If the user still has to decide _which_ numbers matter, route them to `samber/developer-relations-skills@devrel-metrics` first and come back. ## Which numbers you may cite The mechanics of this field are documented: retention windows, download-counting policies, blocking rates, the one published naming framework. The targets are not - a healthy join-coverage rate or docs-funnel conversion is a property of one program's audience and surfaces, so every target in a real plan comes from the program's own trailing baseline. Hold that line in everything you write. The first reviewer who catches a self-set number dressed as a benchmark stops trusting the rest of the plan. - **Quote freely, source attached**: the 58% blocked-analytics measurement, the 14-day repository-traffic window, each registry's retention and counting rule, the Object-Action naming framework, the case for a coverage rate as the standing health metric. Full list with citations in [references/published-findings.md](references/published-findings.md). - **Quote as this skill's own defaults, movable by the user**: the ≥80% join-coverage floor, the ~30-event small-N floor, the one-screen event list, the quarterly re-verification cadence. - **Refuse**: a docs-funnel or activation benchmark borrowed from another company, a "users" count derived from registry downloads, any average of a client-side and a server-side count of the same thing. ## Interview Ask these one at a time, multiple-choice where you can. Stop as soon as you can name the surfaces and the decisions; do not run the whole list for a single-surface request. 1. Which decisions should this data change? Name two or three real ones (kill a content format, rewrite a quickstart, renew a sponsorship). 2. Which surfaces do you own? Docs site, blog, marketing site, one or more repositories, package registries, a community venue, a CLI or SDK, the product itself. 3. Which surfaces do you _not_ own but still get traffic from? Talks, podcasts, other people's posts, aggregators. 4. What is already instrumented, and who owns it? 5. Is the adoption motion individual self-serve, company buying, or both? This decides whether events roll up to an account. 6. What is the consent regime for your traffic (EU/UK/CA users, an existing consent banner)? 7. Who implements - the docs/web team, a data team, or you? 8. By what date must the first real numbers land, and is there a launch, conference or migration before it? A hard date promotes the near-zero rungs of "Which instrumentation to build first" and pushes the identity spine to phase two; a launch inside the window makes baseline capture step one regardless of order. 9. Do you want a one-off answer to one question, or an asset that keeps paying? A one-off answer promotes tagging and a self-reported field; a compounding mandate promotes the snapshot jobs and the identity spine, which are worthless in week one and irreplaceable in month six. 10. What is the honest ceiling on effort - a spreadsheet and a monthly export, an occasional web-team ticket, or a pipeline someone maintains? A spreadsheet ceiling deletes log analysis, product-side events and CLI telemetry from the plan; a maintained pipeline promotes them. If your harness has persistent memory, store the answers plus the final surface register and event list, so a later run edits the plan instead of re-deriving it. ## Workflow 1. **Write the decision list first.** One line per decision, with the question that would settle it. Every event in the plan must trace back to a line here. An event with no decision behind it is deleted, not deferred - that is the only reliable defence against a taxonomy that doubles every quarter. 2. **Build the surface register.** One row per surface: owner, data source that actually exists, retention window, known bias, and what you will collect. Read [references/surface-register.md](references/surface-register.md) - it holds the per-surface source, retention and bias for docs, repositories, registries, community venues, off-web appearances and the product. 3. **Apply the developer-audience correction.** Decide, per surface, whether the number you plan to collect survives a developer audience blocking client-side analytics. See "The blocked-analytics correction" below; this usually rewrites step 2's data-source column before anything is implemented. 4. **Order what gets built.** The register names more instrumentation than any team ships at once. Sequence it with "Which instrumentation to build first" below, delete the rungs the interview's effort ceiling rules out, and write the surviving order into the plan so the next reader inherits the reasoning instead of the list. 5. **Set the identity spine.** Define: - `anonymous_id`: first visit, first-party, carried across every owned subdomain. - `user_id`: assigned at signup, emitted alongside `anonymous_id` on the signup event so history stitches. - `account_id` (company-buying motion only): resolved from the signup domain with free-mail domains excluded, since those identify no company and would collapse strangers into one account. Mark the surfaces that can never be resolved to a person. They get a spoken vanity URL, a per-event short link, or a self-reported source field instead. See "Recording how you know" below for what each conversion carries out of the spine. 6. **Write the event taxonomy.** - Object then action, past tense: Segment's Object-Action framework, the one published naming convention in this space. - Put context in properties, never in the name. The framework's own examples follow this without stating it as a rule. - Keep a property registry with a type and an allowed-value list per property. - Ban PII and PII-shaped identifiers from every property. 7. **Write the link-tagging convention.** Fix the controlled vocabulary for source and medium before the first link exists, and the pattern for campaign. See "Link tagging" below. 8. **Define the funnel views.** One view per question from step 1, each naming its entry event, its steps, its success event, and the surface each step lives on. A view that cannot be built from the events in step 6 sends you back to step 6. 9. **Capture baselines and start snapshotting.** Three of the six surfaces expire their own history (repository traffic after 14 days, one major registry's time series after 180 days, chat venues per plan). Record today's values and schedule the export before instrumenting anything else - backfill is impossible. 10. **Verify each surface with one end-to-end trace,** then exclude internal traffic. Follow [references/verification-playbook.md](references/verification-playbook.md). A green debugger is not evidence; the trace is. 11. **Ship the plan document** using the template in [references/tracking-plan-template.md](references/tracking-plan-template.md), with a version, an owner, and a review trigger. Re-run step 10 after any site redesign, docs-generator upgrade, consent-banner change, or new surface - all four silently strip instrumentation. ## The blocked-analytics correction Developer audiences block client-side analytics at rates no marketing playbook assumes. Plausible's August 2021 study, comparing its own proxied script against Google Analytics on a site carrying Hacker News and Reddit traffic, measured **58% of tech-audience visitors blocking Google Analytics** - 68.2% on desktop, 88.3% on Firefox, and 82.3% on Linux. What that forces into the plan: - A third-party analytics script on a docs site measures roughly the non-developer half of a developer audience, and the miss rate varies by page. A Linux install page is blocked far harder than a pricing page, so the bias is not even a constant you can divide out. - Trust ratios inside one source over absolutes across sources. Step-to-step drop-off on the quickstart survives the correction; "monthly docs sessions" does not. - Never average a blocked client-side number against a server-side one to "split the difference". Label each number with the source it came from and reconcile the gap explicitly. - Consent denial removes measurement one-for-one on the surfaces it covers; treat the consented share as a sample, and say so in every report built on it. ## Which instrumentation to build first The register names eight buildable things, and they differ by two orders of magnitude in what they cost to stand up. Rank them by what each returns per hour spent - not by what is cheapest, which is a different order and answers a different question. - efficiency (value per hour - the default build order): tagging vocabulary > snapshot jobs > self-reported source field > docs event collection > identity spine > log analysis > product-side events > CLI/SDK telemetry - effort (heaviest first): CLI/SDK telemetry > product-side events > identity spine > docs event collection == log analysis > snapshot jobs > tagging vocabulary == self-reported source field - value (strongest evidence first): identity spine > product-side events > docs event collection > snapshot jobs > tagging vocabulary > log analysis > CLI/SDK telemetry > self-reported source field - compliance cost (heaviest review first): CLI/SDK telemetry > product-side events > identity spine > docs event collection > self-reported source field > log analysis > snapshot jobs == tagging vocabulary The three ties are genuine ones: - Tagging vocabulary and the self-reported field: both are a decision written down rather than code, so neither can be made cheaper than the other. - Docs event collection and log analysis: each is about a week of somebody else's sprint, one on the site and one on the pipeline. - Snapshot jobs and the tagging vocabulary: both touch only public counts and query strings, so neither reaches a person and neither triggers a review. In efficiency order, with the trade-off folded into each rung: 1. **Tagging vocabulary and link registry** - an hour of decisions, no engineering. Every future external link becomes readable, and the decision is unrepeatable: links published before the vocabulary exists stay unmergeable forever. 2. **Snapshot jobs for the expiring surfaces** - an hour to write, then a standing job. Buys the only history that cannot be bought later; repository traffic is gone in 14 days and one registry's series in 180. 3. **Self-reported source field at signup** - near-zero. The only signal that exists at all for talks, podcasts and hallway conversations, and weak everywhere those are not the question. 4. **Docs event collection on a first-party or proxied script** - about a week of web-team work. Recovers the developer half of the audience that a third-party script never saw, and makes quickstart drop-off measurable. 5. **Identity spine and the cross-domain stitch** - a week of engineering if you own both domains, a quarter if you do not. The strongest evidence in the plan and the only thing that answers whether a surface produces signups. 6. **Server or CDN log analysis** - about a week of data work. Raw unblockable reach, no behaviour, no funnel; a sanity check on the client numbers rather than a replacement. 7. **Product-side events** - a quarter, most of it negotiating with the team that owns the stream. Settles activation and behaviour-change claims that nothing upstream can. 8. **CLI/SDK telemetry** - a standing job plus a trust cost paid in the community, not in hours. Answers real-usage questions no other surface reaches, and a surprise here costs more goodwill than the data returns. Default: ship rungs 1-3 in the first week, then stop and re-read the decision list. Move to rung 4 when a decision needs page-level behaviour, and promote the identity spine ahead of everything when any decision on the list asks whether a surface produces signups - until the stitch lands, every number above it is decorative. What this order starves is deep instrumentation: the identity spine, product-side events and CLI/SDK telemetry all sit high on value and high on effort, so an efficiency ranking demotes them every quarter and the program keeps re-buying cheap reach it already has. Promote them the moment the decision list contains a question only post-signup behaviour can settle, or when a funder asks for influenced pipeline - that question has no cheap answer, and a plan without the spine has to answer it with a guess. Delete rather than demote. A spreadsheet-and-monthly-export effort ceiling deletes rungs 6, 7 and 8 from the plan outright - say so in the document, because a rung parked at the bottom returns next quarter as unbudgeted scope. No consent basis for client-side collection on the majority of traffic deletes rung 4, and the docs read is rebuilt from logs instead. This order is a default, not a law: it shifts with context and with who executes it. Re-rank it against what you already know about this team. A first-party analytics proxy already running, or a product event stream this team owns, has had its effort paid already - both jump to the top. A team whose only real surface is a repository has no rung 4 at all. ## Recording how you know Step 5 decides who a conversion belongs to; this section decides what you can claim about where it came from. A bare channel written onto a record gets treated as fact by everyone downstream. Carry three fields instead of one on every conversion the plan reports - a practice from the production runbook of DevRel practitioner Tessa Kriesel (citations in [references/published-findings.md](references/published-findings.md)): - `source` - the channel. - `source_basis` - the evidence type: `journey_linked` (the identity chain resolved), `self_reported` (the human answered), `campaign_window` (a heuristic guess). - `source_confidence` - judged on the quality of the evidence, never read off the basis. A journey-linked touch that arrived with a malformed tag is lower confidence than a specific self-report; a vague self-report is lower than both. Report basis and confidence together - either one alone gets the whole record distrusted. Three rules from the same runbook keep the fields honest: - **Fail closed.** When the merge is ambiguous, record nothing. A missing journey is a gap someone can see and fix; a wrong merge is corruption nobody later detects. - **Guess narrowly.** The campaign-window heuristic - attributing an unlinked conversion to whatever was running in its window - is a real signal only when three conditions pin it to a single source: the date falls inside exactly one campaign's window, the landing page belongs to that campaign, and its tags were live. Overlapping campaigns or a shared landing page break the pin; write `unknown`. Used bluntly, the heuristic manufactures attribution instead of recovering it. - **Never overwrite.** Backfill only records whose source is blank, never one already carrying a journey-linked or self-reported value, and keep backfilled history visually separate so it is not read as a trend. Expect near-zero attributed conversions until the cross-domain stitch is verified in production, then a jump the week it lands. That jump is instrumentation, not growth - annotate it before someone reports it as a win. ## Event taxonomy For the good/bad naming pattern, see [references/tracking-plan-template.md](references/tracking-plan-template.md#event-naming-good-vs-bad). Rules that survive a year: - Write events and properties in lowercase snake_case, so a hand-typed identifier can never mismatch on case. That is this skill's convention, not the framework's - Segment prescribes no casing and rules only that consistency matters. - Match an existing plan's casing instead of converting it. Consistency is the sourced rule; any particular case never was. - One event per user intent, never per UI element - renaming a button must not fork the event's history. - Renaming a shipped event splits its history in two. Add a property instead, or version the plan and note the break. - Keep the event count small enough that the whole list fits on one screen. A taxonomy nobody can read is a taxonomy nobody follows. - Emit the same event name for the same intent across surfaces, and let a `surface` property carry the difference. ## Link tagging - Fix an allowed list for source and medium before the first tagged link. An open vocabulary produces `Twitter`, `twitter`, `X` and `x.com` as four sources inside a month, and no report can merge them afterwards. - Lowercase everything, one separator character, no spaces. - Tag only links a third party clicks _into_ your site. Tagging an internal docs link restarts the session and overwrites the real source with your own - the most common self-inflicted attribution wound on a docs site. - Tag per artifact, not per campaign, whenever the point is comparing artifacts: which post, which sample repo, which event page. - Register every published tagged link in one table with owner and publish date. An unregistered tag is unreadable six months later. - Redirect chains, shorteners and OAuth hops must preserve the query string, or the tag dies at the hop. - Off-web surfaces cannot be tagged at all. Give each talk or episode a short speakable vanity path, each event a QR code resolving to a tagged URL, and keep one short self-reported source field at signup whose answer list stays stable across quarters. Expect "direct" to remain the largest bucket regardless. Aggregators, chat clients, privacy browsers, PDFs, and slide decks all strip referrers, and roughly 70% of AI-assistant traffic arrives with no referrer at all (Demand Curve #331). A large direct bucket during a launch week is the normal case, not an instrumentation defect. ## Quality gate The plan is not done when it is written; it is done when it passes. Iterate until all four hold, and report the numbers alongside the plan. | Check | Threshold | Where the number comes from | | ------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------- | | Decision coverage | 100% of events trace to a line on the decision list; anything else is cut | definitional | | Verified traces | 100% of primary conversion events traced end to end on their real surface | definitional | | Join coverage | ≥ 80% of primary conversion events resolve to a first touch through the identity spine | **this skill's baseline**, movable by the user | | Tag well-formedness | 100% of published external links validate against the controlled vocabulary | definitional | Treat join coverage as the plan's primary health check - simpler and far more diagnostic than reconciling absolute counts between two tools. Measure it monthly; a sudden drop names the surface that broke. The metric comes from practitioner production use (the same runbook's `journey_linked: false` rate), but no threshold is published anywhere: the 80% is this plan's own floor. State it as such, and replace it with the program's trailing rate once two months of data exist. Two guardrails on the numbers the plan produces: - Below roughly 30 events in a period, publish the raw list with dates instead of a rate. Small-N percentages swing wildly, and DevRel counts (talks, external pull requests, enterprise conversations) are naturally small. - Pair any incentivised volume metric with a quality counter-metric - published posts with organic entries per post, signups with 30-day retention of that cohort - or the number gets gamed the moment it becomes a target. ## Invocation examples | The user says | What you do | What you hand back | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | "We need a tracking plan for our docs and repo before the launch" | Full workflow; capture baselines before anything else, since the launch destroys the pre-period | The plan document, with the surface register, event table, funnel views and a dated baseline table | | "Our GitHub traffic numbers vanished" | Skip to the surface register; explain the 14-day window and schedule a daily export | A one-page collection recipe plus the snapshot job's schedule and owner | | "Docs sessions dropped 40% after the redesign" | Re-verification trace first, before any analysis | A findings table (result, severity, confidence, evidence, owner) - not a traffic explanation | | "Which blog posts drive signups?" | Link-tagging convention, per-artifact tags, plus the self-reported field; state the direct-bucket ceiling upfront | The tagging vocabulary, the registry table, and the one funnel view that answers it | One request gets a refusal instead of a deliverable: "set us a target for docs conversion rate." A conversion target borrowed from another program's funnel measures that program's audience, not this one, so decline the borrowed number, route target-setting to `samber/developer-relations-skills@devrel-metrics`, and offer the baseline-capture plan that would produce a real target. The default deliverable is one markdown document following [references/tracking-plan-template.md](references/tracking-plan-template.md): decisions, surface register, build order, identity spine, event table, property registry, tagging vocabulary, funnel views, baselines, quality-gate results, known gaps. A single-surface request gets the same shape with the irrelevant sections dropped, never a different shape. ## Failure modes | Symptom | Likely cause | Fix | | ----------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Docs traffic looks tiny next to registry downloads | client-side script blocked by the audience | proxied/first-party collection, or read server/CDN logs | | Registry downloads spike with no other movement | CI, mirrors and analysis bots counted as installs | switch to the registry's mirror-excluded series where one exists; compare to its own baseline only | | Repository traffic history gone | forge traffic endpoints keep 14 days | schedule an export from day one; the gap is unrecoverable | | Every session's source is your own docs | UTM tags on internal links | strip tags from internal links, exclude your own domains from source classification | | Conversions counted twice | confirmation page reachable by refresh, or two collectors firing | unique event ID per conversion, deduplicate on it | | Signups have no history before signup | `anonymous_id` not emitted with the signup event | fix the stitch first; every upstream number is unusable until it lands | | Two tools disagree on the same metric | different definitions, windows, timezones or counting rules | refuse to sum them; publish both with their definitions and reconcile the delta | | Numbers look great, nobody acts on them | events were chosen from what was easy to collect | rebuild from the decision list in step 1 | | Attributed conversions jump the week the stitch ships | the spine only started resolving then | annotate the date; compare only within the post-stitch period until a full cycle has passed | | A verified source was replaced by a channel guess | a backfill job overwrote populated rows | restore, then restrict backfill to blank sources and tag every backfilled row with its basis | | Strangers merged into one giant account | domain matching included free-mail domains, which identify no company | exclude free-mail-class domains from account matching | | Every account holds exactly one person | signup domains never resolved to a company | fall back to enrichment or manual matching, and report what share resolved | ## Privacy gate Clear this before shipping, not after: - Aggregate anything person-level. - Keep PII out of properties (hashing is not consent). - Publish no per-member leaderboard without consent. - Check a venue's terms before bulk-exporting its content. - Honour data-retention and deletion obligations on every store you create. Community and contributor data is person-level by default, which is exactly where this bites. ## Reference - [references/surface-register.md](references/surface-register.md) - per-surface data source, retention window, bias and collection recipe, plus the B2B account roll-up. - [references/verification-playbook.md](references/verification-playbook.md) - the end-to-end trace procedure, internal-traffic exclusion, and the re-verification triggers. - [references/tracking-plan-template.md](references/tracking-plan-template.md) - the output document template with a worked example and a good/bad row pair. - [references/published-findings.md](references/published-findings.md) - every sourced figure with its citation, this skill's own baselines, the claims to refuse, and a negative example of a baseline laundered into a standard. - `samber/developer-relations-skills@developer-journey-map` - for the stage model the funnel views should mirror. - `samber/developer-relations-skills@developer-community-health` - for community metric definitions; instrument them here, define them there. - `samber/developer-relations-skills@docs-seo` - for search-side measurement of a docs site, which uses a source this plan does not cover. - `samber/developer-relations-skills@developer-quickstart-guide` - for the first-success funnel this plan's enablement events feed.
Ships with 5 supporting files:
- evals/evals.json
- references/published-findings.md
- references/surface-register.md
- references/tracking-plan-template.md
- references/verification-playbook.md
Mirrored from the author's public source. Install counts from the open skills registry.