<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ProtoConsent</title>
    <description>The latest articles on DEV Community by ProtoConsent (@protoconsent).</description>
    <link>https://dev.to/protoconsent</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3898176%2Fb2dc60e1-b9de-4118-9716-2b26ace10f82.png</url>
      <title>DEV Community: ProtoConsent</title>
      <link>https://dev.to/protoconsent</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/protoconsent"/>
    <language>en</language>
    <item>
      <title>An open API for composable privacy extensions</title>
      <dc:creator>ProtoConsent</dc:creator>
      <pubDate>Sun, 26 Apr 2026 01:52:24 +0000</pubDate>
      <link>https://dev.to/protoconsent/an-open-api-for-composable-privacy-extensions-cgo</link>
      <guid>https://dev.to/protoconsent/an-open-api-for-composable-privacy-extensions-cgo</guid>
      <description>&lt;p&gt;&lt;em&gt;How browser extensions can query the user's consent state via a standard protocol&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz241onmr8njfl422jki0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz241onmr8njfl422jki0.png" alt="Inter-extension API log" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: privacy tools that can't talk to each other
&lt;/h2&gt;

&lt;p&gt;The browser extension ecosystem has ad blockers, cookie managers, fingerprint protectors, and VPN clients. Each makes decisions about user privacy independently. None of them knows what the others are doing, and none of them knows what the user actually wants at the purpose level.&lt;/p&gt;

&lt;p&gt;If an ad blocker wants to know whether the user has allowed analytics on a given site, there's no way to ask. If a cookie manager wants to check whether the user has denied ads, it has to implement its own consent model. Every privacy extension reinvents the same wheel, and the user has to configure each one separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  A read-only consent API
&lt;/h2&gt;

&lt;p&gt;ProtoConsent exposes an inter-extension API that lets other browser extensions query the user's consent state. The protocol uses &lt;code&gt;chrome.runtime.sendMessage&lt;/code&gt; with ProtoConsent's extension ID as the target. The API is read-only: consumer extensions can read preferences but never modify them.&lt;/p&gt;

&lt;p&gt;Two message types are supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capabilities discovery&lt;/strong&gt;: the consumer asks what the provider supports (protocol version, available purposes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent query&lt;/strong&gt;: the consumer asks for the user's consent state on a specific domain. The response contains all six purposes as booleans, plus the active profile name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A consent query looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Query&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;protoconsent:query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;protoconsent:response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;purposes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;functional&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;analytics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;personalization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;third_parties&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;advanced_tracking&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;balanced&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One domain per request. No bulk queries. The response contains only the fixed six-purpose schema, a profile name, and a version string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust on first use
&lt;/h2&gt;

&lt;p&gt;The API is disabled by default. The user must explicitly enable it in ProtoConsent's settings. Even then, each consumer extension must be individually approved.&lt;/p&gt;

&lt;p&gt;On first contact from an unknown extension, ProtoConsent stores a pending authorization request and responds with a &lt;code&gt;need_authorization&lt;/code&gt; error. The user can then approve or deny the extension from the settings UI. This is a &lt;strong&gt;TOFU (Trust on First Use)&lt;/strong&gt; model: no extension gets access without the user's explicit approval.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Approved extensions are stored in an allowlist.&lt;/li&gt;
&lt;li&gt;Denied extensions are moved to a denylist. Future messages from denied extensions are silently dropped, giving no signal that ProtoConsent is active.&lt;/li&gt;
&lt;li&gt;The pending queue is capped at 10 entries to prevent flooding.&lt;/li&gt;
&lt;li&gt;A global cooldown limits new unknown extension IDs to 3 per minute.&lt;/li&gt;
&lt;li&gt;Approved extensions are rate-limited to 10 requests per minute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Privacy tools today are silos. Each one has its own model of what the user wants, its own configuration UI, and its own enforcement rules. The result is duplication, inconsistency, and cognitive load for the user.&lt;/p&gt;

&lt;p&gt;An open consent API changes this. A cookie manager could check whether the user has allowed analytics before deciding what to clean. A content blocker could query purpose preferences before applying its rules. A fingerprint protector could adapt its behavior based on whether the user has denied advanced tracking on a given site.&lt;/p&gt;

&lt;p&gt;The user configures their preferences once, in one place. Other tools read those preferences and adapt. That's composable privacy: tools that work together instead of side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security by design
&lt;/h2&gt;

&lt;p&gt;The protocol is designed to be safe by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-only&lt;/strong&gt;: there is no code path from external messages to storage writes or rule changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sender verification&lt;/strong&gt;: &lt;code&gt;sender.id&lt;/code&gt; is provided by the browser and cannot be forged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No intrusive prompts&lt;/strong&gt;: authorization requests are queued silently and reviewed at the user's discretion. No popup windows, no clickjacking vectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observable&lt;/strong&gt;: all inter-extension events (successes, errors, rate limits) are visible in the extension's log, timestamped and color-coded.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cross-browser compatibility
&lt;/h2&gt;

&lt;p&gt;The protocol works identically on Chrome and Firefox. Both support &lt;code&gt;chrome.runtime.onMessageExternal&lt;/code&gt; and runtime sender verification. ProtoConsent omits &lt;code&gt;externally_connectable&lt;/code&gt; from the manifest, giving open access on both browsers. Security is enforced at runtime (opt-in, allowlist, rate limiting), not at the manifest level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;A minimal test consumer extension is available in the &lt;a href="https://github.com/ProtoConsent/ProtoConsent" rel="noopener noreferrer"&gt;source repository&lt;/a&gt; under &lt;code&gt;examples/test-consumer/&lt;/code&gt;. It sends capabilities queries, consent queries, invalid inputs, and rate-limit tests, and logs responses in a popup panel.&lt;/p&gt;

&lt;p&gt;ProtoConsent is free and open source (GPL-3.0+). The inter-extension protocol is part of the draft specification and open to feedback.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A .well-known file for website privacy declarations</title>
      <dc:creator>ProtoConsent</dc:creator>
      <pubDate>Sun, 26 Apr 2026 01:46:22 +0000</pubDate>
      <link>https://dev.to/protoconsent/a-well-known-file-for-website-privacy-declarations-2f16</link>
      <guid>https://dev.to/protoconsent/a-well-known-file-for-website-privacy-declarations-2f16</guid>
      <description>&lt;p&gt;&lt;em&gt;How websites can declare their data practices in a machine-readable format&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrbte32utk8ghqibx53l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrbte32utk8ghqibx53l.png" alt="Site declaration in the extension" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Most websites have a privacy policy. Most people don't read them. What if a website could declare its data practices in a machine-readable format that a browser extension could read, display, and compare against the user's preferences?&lt;/p&gt;

&lt;p&gt;That's what &lt;code&gt;.well-known/protoconsent.json&lt;/code&gt; does. It follows the same pattern as &lt;code&gt;security.txt&lt;/code&gt; (&lt;a href="https://www.rfc-editor.org/rfc/rfc9116" rel="noopener noreferrer"&gt;RFC 9116&lt;/a&gt;) and &lt;code&gt;.well-known/change-password&lt;/code&gt;: a static file at a standard path that tools can discover and consume automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;A minimal declaration for a blog that uses privacy-friendly analytics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protoconsent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"purposes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"functional"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"legitimate_interest"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Privacy-friendly Analytics"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fixed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"days"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file declares which of ProtoConsent's six purposes the site uses, under what legal basis, with which providers, and for how long data is retained. Purposes not included are treated as "not declared" (the site makes no claim). Setting &lt;code&gt;"used": false&lt;/code&gt; explicitly states a purpose is not active.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six purposes
&lt;/h2&gt;

&lt;p&gt;The declaration uses the same purpose taxonomy as the ProtoConsent extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;functional&lt;/strong&gt; - core site functionality (login, cart, preferences)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;analytics&lt;/strong&gt; - usage measurement and reporting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ads&lt;/strong&gt; - advertising and ad targeting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;personalization&lt;/strong&gt; - content personalization based on user behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;third_parties&lt;/strong&gt; - embedded third-party services (maps, videos, social widgets)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;advanced_tracking&lt;/strong&gt; - cross-site tracking, fingerprinting, user profiling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each purpose, the site can declare: whether it's used, the legal basis (aligned with GDPR Article 6), providers involved, data sharing scope, and retention period.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fuller example
&lt;/h2&gt;

&lt;p&gt;An e-commerce site with ads, analytics, and third-party sharing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protoconsent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"last_updated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"purposes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"functional"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contractual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"session"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Analytics provider"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fixed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"years"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ads"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Ad network"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Retargeting pixel"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sharing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"third_parties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fixed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"months"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"personalization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"until_withdrawal"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"third_parties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"legal_basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sharing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"third_parties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"retention"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fixed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"years"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"advanced_tracking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data_handling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storage_region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"international_transfers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://shop.example.com/privacy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://shop.example.com/privacy#your-rights"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How the extension uses it
&lt;/h2&gt;

&lt;p&gt;When you visit a site that serves a &lt;code&gt;.well-known/protoconsent.json&lt;/code&gt;, the ProtoConsent extension fetches and validates it. The declared practices are displayed in a side panel alongside the user's own preferences, using &lt;a href="https://consentcommons.com/" rel="noopener noreferrer"&gt;Consent Commons&lt;/a&gt; icons for each purpose.&lt;/p&gt;

&lt;p&gt;This creates a two-column view: what the site says it does (declaration) and what the user wants (preferences). Users can see at a glance whether a site's stated practices align with their choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-assertion, not certification
&lt;/h2&gt;

&lt;p&gt;The declaration is a voluntary, self-asserted transparency signal. It does not change how the extension enforces user preferences. Publishing a &lt;code&gt;protoconsent.json&lt;/code&gt; file does not prove actual technical behavior: a site could declare &lt;code&gt;"ads": { "used": false }&lt;/code&gt; while still loading ad trackers. The extension always enforces the user's own profile.&lt;/p&gt;

&lt;p&gt;Think of it like &lt;code&gt;security.txt&lt;/code&gt;: it's a machine-readable way for sites to say "here's what we do" that tools can consume. Trust comes from the declaration being public, inspectable, and comparable against observed behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complementary to existing standards
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPC (Sec-GPC)&lt;/strong&gt;: signals user preference (browser to site). The declaration signals site practices (site to browser). They are complementary directions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ProtoConsent SDK&lt;/strong&gt;: enables dynamic interaction (page queries extension). The declaration enables static discovery (extension reads site). A site can use one, both, or neither.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent Commons&lt;/strong&gt;: the purpose categories and legal basis values align with the &lt;a href="https://consentcommons.com/" rel="noopener noreferrer"&gt;Consent Commons&lt;/a&gt; taxonomy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Publishing a declaration takes a few minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generate&lt;/strong&gt;: use the &lt;a href="https://protoconsent.org/generate.html" rel="noopener noreferrer"&gt;online generator&lt;/a&gt; to create your file interactively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt;: check your file with the &lt;a href="https://protoconsent.org/validate.html" rel="noopener noreferrer"&gt;online validator&lt;/a&gt; or the &lt;a href="https://github.com/ProtoConsent/validate-action" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt; for CI/CD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt;: place the file at &lt;code&gt;/.well-known/protoconsent.json&lt;/code&gt; on your domain. For GitHub Pages, add a &lt;code&gt;.nojekyll&lt;/code&gt; file so the &lt;code&gt;.well-known&lt;/code&gt; directory is served.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List your site&lt;/strong&gt;: add it to the &lt;a href="https://protoconsent.org/directory.html" rel="noopener noreferrer"&gt;public directory&lt;/a&gt; of sites with declarations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the full specification, see &lt;a href="https://github.com/ProtoConsent/ProtoConsent/blob/main/design/spec/protoconsent-well-known.md" rel="noopener noreferrer"&gt;protoconsent-well-known.md&lt;/a&gt; on GitHub. The &lt;a href="https://github.com/ProtoConsent/ProtoConsent/blob/main/docs/schema/v0.2.json" rel="noopener noreferrer"&gt;JSON Schema&lt;/a&gt; (v0.2) is also available for programmatic validation.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>json</category>
    </item>
    <item>
      <title>Purpose-based consent: a missing layer in the browser</title>
      <dc:creator>ProtoConsent</dc:creator>
      <pubDate>Sun, 26 Apr 2026 01:43:34 +0000</pubDate>
      <link>https://dev.to/protoconsent/purpose-based-consent-a-missing-layer-in-the-browser-nl5</link>
      <guid>https://dev.to/protoconsent/purpose-based-consent-a-missing-layer-in-the-browser-nl5</guid>
      <description>&lt;p&gt;&lt;em&gt;Why organizing privacy choices around purposes, not vendors, changes everything&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc8f1g41uq6a4qzuaapy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc8f1g41uq6a4qzuaapy.png" alt="Purpose-based privacy control" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with consent today
&lt;/h2&gt;

&lt;p&gt;There is no browser-level place where a user can say "I allow analytics but not ads on this site" and have it enforced consistently. Privacy choices today are scattered across per-site dialogs, each with different language, different categories, and different defaults. The result is not informed consent - it is consent fatigue.&lt;/p&gt;

&lt;p&gt;Existing tools sit at two extremes. Content blockers operate on domains and filter lists: effective, but blunt. Consent management platforms (CMPs) operate per site and per vendor: flexible for the site, opaque for the user. There is no browser-level layer in between where you can express intent by purpose and have it enforced consistently across sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why purpose-based
&lt;/h2&gt;

&lt;p&gt;ProtoConsent organizes decisions around &lt;em&gt;purposes of data use&lt;/em&gt;: functional, analytics, ads, personalization, third-party services, and advanced tracking. Not around vendors, cookies, or domains.&lt;/p&gt;

&lt;p&gt;Purpose is the only abstraction that connects three things simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regulation&lt;/strong&gt;: major privacy frameworks organize consent around purpose limitation. GDPR, CCPA/CPRA, LGPD, PIPL, PIPA, and APPI all use purpose as the fundamental unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human comprehension&lt;/strong&gt;: people think "I don't want ads tracking me", not "I don't want requests to doubleclick.net". Purpose maps to how users actually reason about their choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viable enforcement&lt;/strong&gt;: purposes can be mapped to domain categories and filter rules that browser extension APIs can enforce at the network level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A vendor-based model would fragment decisions across hundreds of entities. A cookie-based model would ignore network-level tracking. Purpose sits at the right level of abstraction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why browser-level
&lt;/h2&gt;

&lt;p&gt;ProtoConsent places enforcement in the browser, not in the site or in a backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No delegation to sites&lt;/strong&gt;: enforcement does not depend on each site honoring preferences. The browser blocks requests before they leave your device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No backend&lt;/strong&gt;: no central server, no accounts, no cloud sync. All state is local.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: the same choice applies the same way across sites, rather than being re-negotiated per banner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser is the only place where you can block requests, emit privacy signals like &lt;a href="https://globalprivacycontrol.org/" rel="noopener noreferrer"&gt;GPC&lt;/a&gt;, and show the user what happened, all without introducing new remote points of control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Express, enforce, observe
&lt;/h2&gt;

&lt;p&gt;ProtoConsent starts from a single premise: consent is only meaningful if the user can &lt;strong&gt;express&lt;/strong&gt; it in understandable terms, &lt;strong&gt;enforce&lt;/strong&gt; it technically, and &lt;strong&gt;observe&lt;/strong&gt; its effects. If any of the three is missing, the system fails.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Express&lt;/strong&gt;: per-site profiles and purpose toggles let you say "on this site, allow analytics but deny ads" from a single popup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforce&lt;/strong&gt;: the browser blocks requests associated with denied purposes before they leave your device. A conditional &lt;a href="https://globalprivacycontrol.org/" rel="noopener noreferrer"&gt;GPC&lt;/a&gt; signal is sent per site, with legal weight under CCPA/CPRA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observe&lt;/strong&gt;: blocked request counters, a real-time log, and per-domain purpose attribution show you exactly what enforcement does.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a feedback loop: the user decides, the browser enforces, the user sees the result. Consent becomes a process, not a single click.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcement is a means, not an end
&lt;/h2&gt;

&lt;p&gt;ProtoConsent uses curated blocklists to enforce user choices, but blocking is not the goal: it is the mechanism that makes consent meaningful. The current core set is built from public blocklists, organized by purpose, with cross-source validation and an explicit safelist. Path-based precision (blocking &lt;code&gt;google.com/pagead/&lt;/code&gt; instead of all of &lt;code&gt;google.com&lt;/code&gt;) prioritizes correctness over exhaustiveness.&lt;/p&gt;

&lt;p&gt;Optional extended lists provide broader coverage with curated third-party sources for users who want it, without changing the core model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voluntary site cooperation
&lt;/h2&gt;

&lt;p&gt;ProtoConsent supports two optional ways for websites to participate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Site declarations&lt;/strong&gt;: a website publishes a &lt;code&gt;.well-known/protoconsent.json&lt;/code&gt; file declaring its purposes, legal bases, and providers. The extension displays it alongside user preferences. It is a transparency signal, not enforcement evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK&lt;/strong&gt;: websites can query the user's consent state per purpose and adapt their behavior accordingly. The SDK is read-only and returns &lt;code&gt;null&lt;/code&gt; if no extension is present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both paths are optional. ProtoConsent works without any site integration. Sites that cooperate add transparency, not a requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ProtoConsent is not
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a replacement for dedicated ad blockers&lt;/strong&gt;: its core goal is purpose-based consent enforcement. Enhanced Protection provides substantial blocking out of the box, but the focus is purpose attribution and user control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a consent management platform&lt;/strong&gt;: it does not manage consent on behalf of sites or negotiate with vendors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a VPN or anonymity tool&lt;/strong&gt;: browser-level enforcement cannot prevent server-side processing or offline correlation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a legal compliance tool&lt;/strong&gt;: it provides technical mechanisms for consent, not legal adjudication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ProtoConsent adds a layer that didn't exist: a personal consent control panel in the browser, organized around purposes, that can work alongside the tools you already use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;ProtoConsent is free and open source (GPL-3.0+ for the extension, MIT for the SDK). Available on the &lt;a href="https://microsoftedge.microsoft.com/addons/detail/protoconsent/djghmcahfjgmeiocpgkdgengofconfoo" rel="noopener noreferrer"&gt;Edge Add-ons Store&lt;/a&gt;. Try the &lt;a href="https://demo.protoconsent.org" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;, or read the &lt;a href="https://protoconsent.org/developers.html" rel="noopener noreferrer"&gt;developer guide&lt;/a&gt; to integrate your site.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/ProtoConsent/ProtoConsent" rel="noopener noreferrer"&gt;github.com/ProtoConsent/ProtoConsent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
