Skip to content

Commit 726f6dd

Browse files
docs(sponsors): allow standard UTM parameters in sponsor links (#445)
Policy update. Rule 4 changes from a blanket ban on tracking parameters to a narrower link policy: standard UTM parameters (utm_source, utm_medium, utm_campaign) are permitted so sponsors can measure traffic, while affiliate/referral parameters, redirect chains and analytics injection remain forbidden. The guard in render_sponsors.py is narrowed to match — it is a blocklist rather than an allowlist on purpose, since sponsors legitimately use product parameters (?plan=pro, ?lang=en) the policy says nothing about. Verified across 10 cases, including a mixed URL where UTM is accepted but a smuggled ref= is still rejected. Also folds in the rest of the revised policy: - sponsorships run through GitHub Sponsors; one-time options live on that page - rule 6 covers sponsor-submitted assets, with placement confirmed in writing - rule 8 drops the invoice route - "How to start" now flows sponsor-first, then email the logo and target URL The download figure stays "130K+ total" (measured: pepy 130,827 total; pypistats ~6.9K/month), not the "100K+ monthly" wording. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 189bded commit 726f6dd

2 files changed

Lines changed: 39 additions & 19 deletions

File tree

SPONSORSHIP.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Sponsorship keeps the project maintained, secure, and free.
66

77
## Placements & tiers
88

9-
All amounts are monthly. One-time placements available at 2× the monthly rate for a 30-day run.
9+
All sponsorships run through [GitHub Sponsors](https://github.com/sponsors/yusufkaraaslan). All amounts are monthly.
1010

1111
| Tier | Price | What you get |
1212
|------|-------|--------------|
@@ -16,7 +16,7 @@ All amounts are monthly. One-time placements available at 2× the monthly rate f
1616
| **Gold** | $400/mo | Large logo near the top of the README sponsor section + website placement + mention in release notes |
1717
| **Platinum** | $1,000/mo | Everything in Gold + a short "Sponsored" blurb (1–2 sentences, your copy, my approval) in the README + priority issue triage |
1818

19-
Custom arrangements (integrations, co-marketing, content) are quoted case by case.
19+
One-time options are available on the Sponsors page. Custom arrangements (integrations, co-marketing, content) are quoted case by case.
2020

2121
## Rules — read before reaching out
2222

@@ -25,25 +25,30 @@ These are non-negotiable and exist because I've been through enough of these dea
2525
1. **Relevance filter.** Sponsors must be tools or services genuinely useful to developers working with AI tooling, docs infrastructure, or open source. I decline everything else regardless of budget.
2626
2. **Clear labeling.** All paid placements are explicitly marked "Sponsor" or "Sponsored." No native-ad ambiguity.
2727
3. **No editorial control.** I don't write reviews or recommendations with predetermined conclusions. A sponsorship buys placement, not my endorsement. If I recommend your tool anywhere, it's because I use it and it earned it.
28-
4. **No tracking parameters.** Sponsor links are clean URLs. No UTM tags, no redirect chains, no analytics injection.
28+
4. **Link policy.** Sponsor links may include standard UTM parameters (`utm_source`, `utm_medium`, `utm_campaign`) for traffic measurement. Affiliate/referral parameters, redirect chains, and analytics injection are not permitted.
2929
5. **Written trail.** All terms are agreed in writing (email is fine) before anything goes live. No chat-only negotiations.
30-
6. **Security review.** Any sponsor-submitted PR (badges, links, integrations) goes through the same security review as any other PR. Credits and placement are confirmed before merge, not after.
30+
6. **Security review.** Any sponsor-submitted asset or PR (logos, badges, links, integrations) goes through the same security review as any other contribution. Placement is confirmed in writing before merge, not after.
3131
7. **Termination.** Either side can end a monthly arrangement with 30 days' notice. I remove placements immediately if a sponsor's product or conduct conflicts with the project's interests.
32-
8. **Payment first.** Placement goes live after the first payment clears ([GitHub Sponsors](https://github.com/sponsors/yusufkaraaslan) preferred; invoice possible for larger tiers).
32+
8. **Payment first.** Placement goes live after the first payment clears via [GitHub Sponsors](https://github.com/sponsors/yusufkaraaslan).
3333

34-
> Rule 4 is enforced in code: `scripts/render_sponsors.py` refuses to render any sponsor URL carrying tracking parameters, and CI fails the build if it finds one.
34+
> Rule 4 is enforced in code: `scripts/render_sponsors.py` accepts standard UTM parameters but refuses to render any sponsor URL carrying affiliate, referral, or click-tracking parameters, and CI fails the build if it finds one.
3535
3636
## How to start
3737

38-
Email **yusufkaraaslan.yk@pm.me** with:
39-
40-
- which tier
41-
- which placement
42-
- your logo and link
43-
- billing contact
38+
Sponsor at the tier you want on **[github.com/sponsors/yusufkaraaslan](https://github.com/sponsors/yusufkaraaslan)**, then email **yusufkaraaslan.yk@pm.me** with your logo (SVG or transparent PNG) and target URL.
4439

4540
If it passes the relevance filter, you'll get written confirmation of terms and a go-live date.
4641

42+
<details>
43+
<summary>What to include in the email</summary>
44+
45+
- the tier you sponsored at
46+
- your logo (SVG or transparent PNG)
47+
- the target URL, including any UTM parameters you want
48+
- a billing/contact address for the written confirmation
49+
50+
</details>
51+
4752
---
4853

4954
## For maintainers

scripts/render_sponsors.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,19 @@
5353
"bronze": "Bronze Sponsors",
5454
}
5555

56-
# SPONSORSHIP.md rule 4: sponsor links are clean URLs - no tracking parameters.
57-
TRACKING_PARAMS = re.compile(
58-
r"^(utm_|ref$|referrer$|fbclid$|gclid$|mc_|_hs|source$|campaign$)", re.I
56+
# SPONSORSHIP.md rule 4 (link policy): standard UTM parameters are allowed for
57+
# traffic measurement. Affiliate, referral and click-tracking parameters are not.
58+
#
59+
# This is a blocklist rather than an allowlist on purpose - sponsors legitimately
60+
# use product parameters (?plan=pro, ?lang=en) that the policy says nothing about.
61+
DISALLOWED_PARAMS = re.compile(
62+
r"^("
63+
r"ref|referrer|referral|refid|" # referral
64+
r"aff|affid|affiliate|partner|pid|" # affiliate
65+
r"fbclid|gclid|msclkid|dclid|twclid|ttclid|irclickid|clickid|" # click IDs
66+
r"mc_[a-z]+|_hs[a-z]*" # mailchimp / hubspot analytics
67+
r")$",
68+
re.I,
5969
)
6070

6171

@@ -64,15 +74,20 @@ class PolicyError(ValueError):
6474

6575

6676
def _assert_clean_url(name: str, url: str) -> None:
67-
"""Reject sponsor URLs carrying tracking parameters (SPONSORSHIP.md rule 4)."""
77+
"""Reject sponsor URLs carrying affiliate or click-tracking parameters.
78+
79+
SPONSORSHIP.md rule 4 permits standard UTM parameters (``utm_source``,
80+
``utm_medium``, ``utm_campaign``) so sponsors can measure traffic, but
81+
forbids affiliate/referral parameters and analytics injection.
82+
"""
6883
query = urlsplit(url).query
6984
if not query:
7085
return
71-
offenders = [k for k in parse_qs(query) if TRACKING_PARAMS.match(k)]
86+
offenders = sorted(k for k in parse_qs(query) if DISALLOWED_PARAMS.match(k))
7287
if offenders:
7388
raise PolicyError(
74-
f"{name}: sponsor URL carries tracking parameters {offenders} - "
75-
f"rule 4 of SPONSORSHIP.md requires clean URLs.\n {url}"
89+
f"{name}: sponsor URL carries affiliate/tracking parameters {offenders} - "
90+
f"rule 4 of SPONSORSHIP.md permits standard UTM parameters only.\n {url}"
7691
)
7792

7893

0 commit comments

Comments
 (0)