Skip to content
Data
Skill

/managing-path-cleaning-rules

Inspects URL paths and proposes, tests, orders, and applies project-level path cleaning rules so dynamic segments (numeric IDs, UUIDs, slugs, dates) collapse into readable aliases. Use when the user says "clean the paths", "normalize URLs", "group similar pages", "too many

From plugin
posthog
38k156 skills11 agents1 command2 MCP
Install
$ npx -y skills add posthog/posthog --skill managing-path-cleaning-rules --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/managing-path-cleaning-rules

Context preview

The summary Claude sees to decide when to auto-load this skill.

Inspects URL paths and proposes, tests, orders, and applies project-level path cleaning rules so dynamic segments (numeric IDs, UUIDs, slugs, dates) collapse into readable aliases. Use when the user says "clean the paths", "normalize URLs", "group similar pages", "too many

SKILL.md

managing-path-cleaning-rules.SKILL.md
name: managing-path-cleaning-rules
description: 'Inspects URL paths and proposes, tests, orders, and applies project-level path cleaning rules so dynamic segments (numeric IDs, UUIDs, slugs, dates) collapse into readable aliases. Use when the user says "clean the paths", "normalize URLs", "group similar pages", "too many distinct paths", "/users/123 and /users/456 are the same page", "set up path cleaning", or asks why a Web analytics or Paths breakdown is fragmented across thousands of nearly-identical URLs. Covers regex syntax (re2), alias placeholder convention, rule ordering, the test workflow, and applying rules via the path-cleaning-rules-update MCP tool.'

Managing path cleaning rules

Path cleaning rules normalize `$pathname` and `$entry_pathname` so that pages sharing the same template (`/users/123/profile`, `/users/456/profile`, …) collapse into one row (`/users/<id>/profile`) in Web analytics tiles, Paths insights, and any HogQL query that calls `apply_path_cleaning`. They are the right answer when a breakdown is fragmented across thousands of near-identical URLs.

This skill teaches you how to:

  • recognize when path cleaning is the right tool
  • inspect real paths to find what needs cleaning
  • write `regex` + `alias` rules in re2 syntax with the project's placeholder

convention

  • test rules before saving them
  • order rules so specific patterns aren't swallowed by generic ones
  • apply the rules via MCP

Data model

`Team.path_cleaning_filters` is a JSON list of `PathCleaningFilter` objects:

{
  "regex": "/users/\\d+/profile",
  "alias": "/users/<id>/profile",
  "order": 0
}
  • **`regex`** — a [re2](https://github.com/google/re2/wiki/Syntax) pattern. No

need to escape `/`. Anchor with `^` / `$` when you mean it.

  • **`alias`** — the literal replacement. Use angle-bracket placeholders

(`<id>`, `<slug>`, `<uuid>`, `<date>`) by convention so the cleaned path stays human-readable. The alias is _not_ a regex template — backreferences are not supported.

  • **`order`** — integer. Rules apply **sequentially** in `order` ascending,

each rule's output feeds the next.

Application is `replaceRegexpAll(pathname, regex, alias)` per rule, chained.

Workflow

1. Confirm path cleaning is the right move

Ask yourself: is the user complaining about cardinality (too many distinct paths in a chart), or do they want a per-URL drill-down? Path cleaning is for the former. If they want per-URL data, suggest a property filter on `$pathname` instead.

2. Inspect the real paths

Don't guess at patterns — query them. With the `execute-sql` MCP tool:

SELECT properties.$pathname AS path, count() AS views
FROM events
WHERE event = '$pageview'
  AND timestamp > now() - INTERVAL 7 DAY
GROUP BY path
ORDER BY views DESC
LIMIT 200

Scan the result for:

  • numeric IDs: `/users/123`, `/orders/4242`
  • UUIDs: `/sessions/8f3c1a3b-…`
  • slugs: `/posts/why-i-love-posthog`
  • dates: `/archive/2024-09-12`
  • locales: `/en-US/`, `/fr-FR/`
  • pagination: `?page=3`, `/page/3/`

3. Draft regex + alias

| Pattern | Example match | `regex` | `alias` | | ------------------- | ---------------------- | ---------------------------- | ---------------------- | | Numeric segment | `/users/123/profile` | `/users/\d+/profile` | `/users/<id>/profile` | | UUID v4 | `/sessions/8f3c1a3b-…` | `/sessions/[0-9a-f-]{36}` | `/sessions/<uuid>` | | Slug | `/posts/why-posthog` | `/posts/[a-z0-9-]+$` | `/posts/<slug>` | | ISO date | `/archive/2024-09-12` | `/archive/\d{4}-\d{2}-\d{2}` | `/archive/<date>` | | Locale prefix | `/en-US/about` | `^/[a-z]{2}-[A-Z]{2}/` | `/<locale>/` | | Trailing query/page | `/blog?page=3` | `\?page=\d+$` | (empty alias drops it) |

Anchoring rules of thumb:

  • start the regex with `^` only when the segment must be at the beginning of

the path

  • end with `$` to keep a generic rule (e.g. `\d+$`) from matching mid-path

segments

4. Test before saving

Three options, pick one:

  • **Settings page tester**: `/settings/project#path_cleaning` has a built-in

"test path" input that replays the full ordered chain.

  • **Project HogQL** (via `execute-sql`):
  SELECT replaceRegexpAll('/users/42/profile', '/users/\d+/profile', '/users/<id>/profile')

Chain `replaceRegexpAll` calls in the same order the rules will run if you want to verify multi-rule interaction.

  • **Built-in AI helper**: there is already an `AiRegexHelper` modal accessible

from the rule editor (`Help me with Regex` button) that turns natural language into a regex. Suggest it to the user when they say "I don't know regex" — but always validate the output against real paths via the tester.

5. Order rules from most-specific to most-general

Sequential application means a generic rule placed first will swallow everything that should have hit a specific rule.

order=0  /users/me/profile        →  /users/me/profile     (specific, runs first)
order=1  /users/\d+/profile       →  /users/<id>/profile
order=2  /users/[a-z0-9-]+        →  /users/<slug>          (catch-all, runs last)

If `/users/[a-z0-9-]+` ran first it would also match `/users/me/profile` and make the more specific rule unreachable.

6. Apply via MCP

Prefer the `path-cleaning-rules-update` tool. It reads the current rules, applies granular operations (`append`, `insert`, `replace`, `remove`, `reorder`), auto-numbers `order`, and — unless you pass `confirm: true` — returns a **preview** of the resulting rules without saving. Pass `sample_paths` to see how the resulting set rewrites real paths.

First call it without `confirm` to get the preview, surface that to the user, then re-send the same call with `"confirm": true` to save:

{
  "operations": [{ "action": "append", "alias": "/users/<id>/profile"
Read more
Ships withposthog

:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.

Get the whole plugin

Other skills on posthog.