A URL that parses is not a URL that is safe

url-utils gives your agent the two things it cannot improvise: the patterns for clean, GA4-correct links, and three scripts that answer PASS or FAIL instead of guessing. Guidance-only, so there is no backend to call and nothing to 404.

13
URL operations
22
installable assets
3
verifier scripts
0
backend calls

Three failures your parser will never report

🔍

Mixed-script homographs

A Cyrillic а inside paypal.com parses cleanly and resolves to a completely different domain. The defense is UTS #46 and UTS #39 mixed-script restriction, not a regex. Single-script domains like münchen.de and 日本.jp stay legitimate and still pass.

🧬

Double percent-encoding

%2541 decodes to %41, then to A. One decode pass leaves a residual payload behind, which is both a filter-evasion signal and a way to break deduplication. The verifier flags it rather than silently normalizing it away.

💸

Auto-tag override

Adding manual utm_source and utm_medium to a Google Ads URL overrides the gclid and breaks GA4 cost attribution. Nothing errors. This is the most expensive mistake, because it corrupts the channel carrying the most spend.

A chalkboard diagram: a white box stamped PARSED with a tick, a broken arrow, and a gold box stamped SAFE with a question mark

Two verdicts, and the arrow between them does not hold.

Three verdicts, not three opinions

Each script prints PASS or FAIL with counts, so the answer is the same every run. Audit mode reports what would change without changing it.

Is this scraped URL safe to store, click, or forward?

node scripts/verify-url.mjs <url>

FAIL  MIXED_SCRIPT_HOMOGRAPH

What would stripping actually remove? (changes nothing)

node scripts/strip-tracking.mjs --mode=audit

42/57 URLs cleaned, avg 3.2 params each

Is this campaign link GA4-correct?

node scripts/lint-utm.mjs <url>

FAIL  invalid medium 'smm'

What you install, instead of what you re-derive

The first version of this skill was a manual. My agent re-read it on every call, reasoned through hex codes and UTM conventions from scratch, and landed somewhere slightly different each time. It scored 100/100 on security and I still called it not useful.

So the shape changed. url-utils now ships 22 registry assets an agent installs once: eight UTM channel templates covering LinkedIn, X, Facebook, Instagram, Threads, email and both paid networks; six per-platform tracking-parameter sets that catch the whole click-ID family rather than just utm_*; four CMS canonical patterns for WordPress, Shopify, Webflow and Next.js; plus fixtures and a homograph allowlist.

One rule outranks everything else. No parameter you have declared attribution-authoritative is ever stripped. Over-stripping is silent and it destroys a client's campaign measurement, so audit mode exists to show you the diff before anything moves.

Questions I get about it

Guidance-only means what, exactly?

There is no API behind this skill and no typed method to call. Every operation is pure logic your agent's own runtime already performs, so it ships the patterns, the assets and the scripts instead of an endpoint. An earlier version declared a backend that did not exist, and a typed call against it would have returned a 404. This shape is the honest one.

Does it reject international domains?

No, and that distinction is the whole point. Rejecting everything non-ASCII would break real customers. münchen.de is Latin with German diacritics and 日本.jp is Han. Both single-script, both legitimate, both pass. What fails is a label that mixes scripts without being on an allowlist.

Why not just strip every utm_ parameter?

Because utm_-only stripping is not URL hygiene. It misses gclid, gbraid, fbclid, msclkid, ttclid, li_fat_id and yclid entirely. The per-platform configs close that gap, and they are snapshot-dated so you know when a set was last checked against the live rulesets.

Do the network operations work in a sandbox?

Expanding a short link and tracing a redirect chain both need outbound HTTP. In a sandboxed runtime they degrade to a cannot-resolve finding rather than crashing, so a locked-down environment loses those two operations and keeps the other eleven.

Stop letting your agent improvise URLs

Install it from the OPVS marketplace, then ask your agent to clean a batch of links, build a campaign URL, or check one before it trusts it.

Install @di-atomic/url-utils