Skip to content

Add tutorial: personalize by account with custom Signals attribute keys - #1890

Draft
jborlase-snowplow wants to merge 6 commits into
mainfrom
tutorial/t2-account-attributes
Draft

Add tutorial: personalize by account with custom Signals attribute keys#1890
jborlase-snowplow wants to merge 6 commits into
mainfrom
tutorial/t2-account-attributes

Conversation

@jborlase-snowplow

Copy link
Copy Markdown
Contributor

What changed?

New tutorial tutorials/signals-account-attributes/ (6 pages + 2 live Console screenshots): track a B2B account entity, define a custom account_id attribute key (Console and SDK tabs), compute cross-user account attributes, and retrieve them with a rule intervention.

Why?

Fills the account-level/custom-attribute-key gap in Signals tutorial coverage (tutorials gap analysis). Existing tutorials only cover the built-in session/user keys.

Reviewer guidance

  • Every code block was executed in page order from a fresh venv against a trial org; attribute values and the intervention were asserted via the Signals API with exact expected values. Console create-key flow verified live; screenshots captured from it.
  • The UUID caveat was tested explicitly: non-UUID account IDs DO compute/retrieve attributes; only intervention subscription rejects them. The sibling python-tracking-and-signals tutorial overstates this — fix proposed separately, not in this PR.
  • The conclusion links /docs/signals/attributes/warehouse-config/ instead of the (unbuilt) warehouse-attributes tutorial; swap when that tutorial lands.
  • Found during verification, flagged for separate follow-up: Console create-key form has no name field (attribute-keys docs outdated); groups 422 if published before their custom key; ~1–2 min engine config-apply lag contradicts "as soon as published" docs wording.

🤖 Generated with Claude Code

New six-page tutorial (tutorials/signals-account-attributes/) showing how
to define a custom attribute key from an entity property, compute
account-level attributes (approx_count_distinct, counter, last) across
all users of a B2B account, and trigger account-level interventions.
Sibling of python-tracking-and-signals, same imaginary SaaS app, now
multi-tenant. All code blocks executed end-to-end against a live
pipeline and Signals environment; Console flow verified with fresh
screenshots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Documentation style review

Scope: writing quality, style guide compliance, terminology, structure, frontmatter, links, MDX components. Nothing here touches technical correctness.

Link check — all internal targets verified to exist (/docs/signals/attributes/attribute-keys/, /docs/signals/attributes/warehouse-config/, /docs/signals/attributes/attributes/, /docs/signals/applications/subscribe/, /docs/signals/attributes/attribute-groups/, /docs/signals/applications/services/, /docs/signals/connection/, /docs/signals/interventions/, /docs/signals/setup/, /docs/signals/, /docs/fundamentals/entities/, /docs/fundamentals/events/, /docs/fundamentals/schemas/, /docs/sources/, /docs/sources/python-tracker/, /docs/event-studio/data-structures/, /docs/api-reference/snowplow-cli/, /docs/testing/snowplow-micro/, plus the sibling tutorial pages). The #self-describing-events anchor is valid. Both added external URLs return 200 (redis.io HyperLogLog, snowplow.io free trial); console.snowplowanalytics.com skipped as auth-gated. Tutorial links correctly omit /index.md per the CLAUDE.md /tutorials exception.

Nice work overall: frontmatter is complete on every page, meta.json matches the sibling python-tracking-and-signals shape, images live in images/ with descriptive filenames and real alt text, and the Tabs block correctly uses mdx-code-block imports with groupId/queryString.


Should fix

1. Troubleshooting sections jump straight from heading to bullets

define-account-attributes.md, retrieve-and-intervene.md, and track-the-account-entity.md all do this:

## Troubleshooting

* `422: Attribute key 'account_id' does not exist`: the group was published before the key.

CLAUDE.md: "Precede every heading with at least one paragraph of explanatory text." Style guide, Page structure: "Precede every heading and list with at least one paragraph of prose", and Lists: "Introduce lists with a sentence ending in a colon."

Add a lead-in to each, for example If publishing fails, check these common errors:.

2. List item capitalization and trailing periods are inconsistent, including within one page

conclusion.md has two lists that follow opposite conventions:

* attached an `account` entity, carrying a UUID-formatted `account_id`, to events from multiple users

* A `workspace_id` or `project_id` entity property, for attributes per workspace or project rather than per tenant.

Style guide, Lists: "Capitalize the first word of each item" and "No period at the end unless the item contains multiple sentences." So the first list should be capitalized, and the first two Variations items (single sentences) should lose their trailing periods.

The lowercase pattern also appears in introduction.md (the "By the end you'll have working code that:" list and the Prerequisites list) and define-account-attributes.md ("an [attribute group]…"). Worth making consistent across the tutorial — noting python-tracking-and-signals/conclusion.md has the same lowercase habit, so this is site-wide drift rather than something introduced here.

3. :::warning used for content that isn't a data-loss or security risk

define-account-attributes.md:

:::warning[Common connection mistakes]

retrieve-and-intervene.md:

:::warning[Interventions fire only once per target]

Style guide, Markdown formatting: "Use Tip for actions, Note or Info for information, Warning for data loss or security risks, Danger for pipeline outages." The first is configuration guidance (:::tip), the second is behavioral information (:::note).

4. Bold on non-UI text

introduction.md:

"you'll compute real-time attributes for a B2B account, rather than for an individual user"

CLAUDE.md: "Use bold only for UI elements (buttons, page titles)." CLAUDE.md wins over the style guide's looser "bold or italic to highlight key phrases". The same word is italicized two paragraphs later — "how active is this *account*" — so this is also internally inconsistent. Drop the bold.

Every other bold in the PR is a genuine UI element and reads correctly.

5. "context" in prose

track-the-account-entity.md:

"Define the account entity once, then attach it to every event as context."

CLAUDE.md: "Use 'entity', never 'context'." Suggest: "Define the account entity once, then attach it to every event." The backticked context= argument references are API names and are fine as-is.

6. "now" as a temporal marker

Style guide, Writing style: "Stay in the present tense. Never use 'currently', 'now', 'in the future', 'latest'." Five instances:

  • define-account-attributes.md: "you can now describe what Signals should compute"
  • define-the-attribute-key.md: "you can now tell Signals to group them by account"
  • retrieve-and-intervene.md: "your application can now look up any account's live profile"
  • define-account-attributes.md: "confirm that your attribute key, attribute group, and service now appear there"
  • track-the-account-entity.md: "Send these events now, rather than waiting until the Signals definitions exist."

Each sentence reads fine with "now" deleted.

7. Article before "Console"

define-account-attributes.md:

"You can also define these in the Console UI."

Style guide, Snowplow terminology: "Console: Capitalized, no article." Suggest: "You can also define these in Console." Every other Console reference in the PR is correct.

8. "easy" is on the banned list

define-account-attributes.md:

"a service that bundles the group for easy retrieval"

Style guide: "Never use marketing language: remove 'effortlessly', 'easily', 'quickly'…". Suggest: "a service that bundles the group so you can retrieve all of the attributes in one call."

9. Six H2 sections on track-the-account-entity.md

Install the SDKs / Create the schemas / Use a UUID for the account ID / Initialize the tracker / Track team activity / Troubleshooting.

CLAUDE.md: "Limit pages to 3-5 H2 sections." Folding "Install the SDKs" into the page intro, or "Use a UUID for the account ID" into "Create the schemas", brings it in line. The other pages are all at five or fewer.

10. Sentence fragments introducing lists

track-the-account-entity.md:

"A task_completed event schema with these properties:"

"An account entity schema with these properties:"

Style guide: "Introduce lists with a sentence ending in a colon" — these have no verb. Suggest "The task_completed event schema needs these properties:" and "The account entity schema needs these properties:".


Nits

11. Stacked admonitions at the end of define-the-attribute-key.md — the page closes with two consecutive :::note blocks, and a third sits inside the Console tab. Style guide: "Use Docusaurus admonitions sparingly." The "Warehouse attribute groups use columns instead" note largely duplicates the warehouse bullet in conclusion.md; consider folding it into prose or dropping it.

12. Unlinked cross-referencedefine-account-attributes.md: "exactly as shown in the previous section". The page links the tracking section elsewhere, so this could link to /tutorials/signals-account-attributes/define-the-attribute-key too.

13. Code identifiers as SEO keywordskeywords: ["...", "AttributeKey", "EntityProperty"] and ["get_service_attributes", "pull_interventions", ...]. CLAUDE.md describes keywords as "Marketing/SEO keywords"; phrase-style entries such as "signals attribute key" or "account-level interventions" search better than symbol names.

14. Question-form admonition title:::note[No entities listed?]. A statement title is more consistent with the rest of the PR, for example :::note[The data catalog refreshes periodically].

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 29, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
documentation 664fbff Commit Preview URL

Branch Preview URL
Jul 31 2026, 10:14 AM

Addresses the blockers, confusions, gaps, and nits raised in the
newcomer-persona review of this tutorial.

Blockers:
- Python prerequisite corrected to 3.11+; every published snowplow-signals
  release declares >=3.11,<4.0, so the first install command failed on 3.9
  and 3.10 with an error that never mentions Python.
- Page 2 now spells out the draft, development, and production states a data
  structure moves through, and that migrating to production is Admin-only.
- New "Confirm your events arrived" step: the tracker logs nothing for a
  non-2xx response and flush() never raises, so the page wires up
  EmitterConfiguration(on_failure=...) and points at Monitoring > Collection
  volumes and Monitoring > Data quality.
- The AttributeKey snippet is restated on page 4 outside the tabs, so
  Console-tab readers aren't left with an undefined name.
- The tracker block prints account_id, and the introduction says to run the
  snippets in one session.

Confusions and gaps: real credential handling via environment variables,
try/except/finally around the final subscription.get(), consistent .get()
access with the empty-profile shape explained, rationale for counting
domain_userid, corrected publish-ordering wording (the SDK publishes by
type, so list order is irrelevant), a bare InterventionCriterion instead of
a single-element Any wrapper, backfill and credential-hygiene notes,
measured waits for the data catalog and config apply, a genuine expected
output block for the full script, and a teardown section in the conclusion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prose and conventions only; no code blocks changed.

- Add lead-in sentences to the three Troubleshooting sections and to the
  conclusion's Next steps, so no heading opens straight into a list.
- Capitalize list items and drop trailing periods from single-sentence ones,
  consistently across all six pages.
- Correct admonition types: the connection-mistakes box is a tip, the
  fire-once and subscription-start boxes are notes. The draft/development
  box stays a warning, since stopping there turns events into failed events.
- Fold "Install the SDKs" into the page intro, bringing the tracking page
  back within the three-to-five H2 limit.
- Drop temporal "now" and "latest", the bold on "account", "in the Console
  UI", "for easy retrieval", and "as context" for entities.
- Introduce lists with complete sentences, fold the stacked warehouse note
  on page 3 into prose, restate the attribute-key link on page 4, and
  replace symbol names in keywords with phrase-style ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jborlase-snowplow

Copy link
Copy Markdown
Contributor Author

Pushed two commits addressing both review tracks:

b7fa4d14 — newcomer-review fixes (an independent fresh-eyes review of the tutorial; findings ranged from a wrong Python prerequisite to silent-failure traps):

  • Prerequisites corrected: Python 3.11+ (every snowplow-signals release requires it), Console permissions incl. the Admin-only production migration
  • The data-structure step now spells out draft → development → production, and a new "Confirm your events arrived" checkpoint (with a real EmitterConfiguration(on_failure=...) example, demonstrated against a deliberate bad host) closes the tutorial's worst failure mode: silent event loss misread as Signals latency
  • The Console tab path no longer dead-ends (the AttributeKey object is restated inline); account_id is printed and the single-Python-session assumption is stated; the final script's climax is guarded instead of ending in an uncaught queue.Empty; a cleanup section was added
  • All code re-executed end-to-end against a live org; the full expected-output block is a genuine capture

6ae7894a — the 14 style-review items — all applied (admonition types, list conventions audited script-wide, H2 counts, keywords, etc.). One deliberate exception: the draft-data-structure warning stays a :::warning because stopping at draft genuinely loses events, which is what the type is reserved for.

Two review findings were confirmed as bugs in other docs pages and deliberately not fixed here: the attribute-keys page's Console tab (name/owner fields that don't exist) and the interventions page typing target_attribute_keys as string[].

🤖 Generated with Claude Code

jborlase-snowplow and others added 2 commits July 30, 2026 17:19
Published tutorials shouldn't carry the Console/API errors or the run
timings from our own verification passes. Sweep all six pages:

- Drop troubleshooting entries that only existed because verification hit
  an error: the 400 on updating a published attribute group, the
  background-thread subscription failure narrative, and the raw 422/400/
  TypeError/ValueError/httpx/KeyError strings.
- Restate the surviving constraints positively: publish the attribute key
  in the same publish() call as the group, intervention subscriptions
  require UUID identifiers, one tracker per namespace per session.
- Remove measured timings (catalog refresh, publish propagation, failed
  event reporting) and describe the waits qualitatively instead.
- Simplify the cleanup section to the working instruction without the
  ordering bug narration; delete() handles dependency order itself.

The "Confirm your events arrived" section, the on_failure emitter example,
the draft/development/production data structure steps, and the
try/except queue.Empty guard all stay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The customer-facing sweep removed the troubleshooting entry that carried
this constraint along with its status code, leaving nothing to tell a
reader iterating on attribute definitions why republishing won't work.
Restate it as guidance in the publish section, matching how the
interventions tutorial and the agentic contexts docs phrase it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jborlase-snowplow

Copy link
Copy Markdown
Contributor Author

Pushed 9516833b + 807f2ea2 — editorial sweep per product direction: verification-run artifacts are out of the reader-facing pages. Error strings and status codes across all troubleshooting sections are restated as positive instructions or checks; measured wait durations are neutral phrasing; the deliberate-failure exercise keeps its teaching value without the run transcript. The published-group immutability constraint is retained as a single positive sentence, phrased consistently with the interventions tutorial and the agentic-contexts docs.

🤖 Generated with Claude Code

Shift the tutorial toward a positive, Console-and-Assistant-first voice with
less process ceremony.

Suggest the Snowplow Assistant as the route for creating the two data
structures, the attribute group, and the service, each with a copy/paste
prompt. The attribute group and service now use the same Tabs pattern as the
attribute key, with Console as the default tab, so the Console reader has a
path through the whole definition set. Move OWNER into the shared connect
block, since the intervention on the next page needs it whichever tab the
reader picked, and offer an Assistant teardown alongside the Python cleanup.

Replace "Confirm your events arrived" with a short verification step: check
event volume and failed events in Console, or ask the Assistant. Drop the
tracker failure-mode taxonomy and the on_failure callback, keeping a brief
pointer that the emitter accepts delivery callbacks.

Remove the timing estimate, the admin-gated Console access paragraph, the
draft/development/production walkthrough and its stop-at-draft warning, the
track-first-so-the-catalog-populates rationale, the publish propagation
paragraph, and four info panels the owner flagged as noise. Make the pages
self-contained by dropping the references to the Python tracking tutorial.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jborlase-snowplow

Copy link
Copy Markdown
Contributor Author

Pushed 664fbffa — product-owner edit round (Console/Assistant-first, less process ceremony):

  • Removed: the time-estimate and Console-permissions paragraphs, the Python-version failure explanation (the 3.11+ prerequisite stays), the draft→development→production walkthrough and admin-only warnings (now simply: both data structures need to be in production), the catalog/propagation panels, "When built-in keys are enough", and "Common connection mistakes"
  • Event verification is now a positive step — check Console metrics, or ask the Snowplow Assistant to verify events arrived / check failed events (copy-paste prompt included)
  • Snowplow Assistant prompts added as the suggested route for creating the data structures and — via new Console-default tabs matching the key section — the attribute group, service, and publish steps. Every prompt's intent was verified against the live API (field-by-field match with the Python definitions; publish exercised; teardown clean)
  • Two verification notes: the deployed account schema has account_id + plan (no name), and prompts match it exactly; owner isn't settable via the Assistant surface — Console defaults it to your user, which the page now states
  • No dependency on the Python tracking tutorial remains; both sibling references removed

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants