Syllabus Lesson 74 of 156 · Third parties on your own site
Third parties on your own site

Permissions-Policy

Why it matters Browsers can reach the camera, microphone, location and more. Your shop needs none of them. If an injected script or an embedded frame asks for the camera on your site, the visitor sees your name in the prompt. Permissions-Policy lets you say "nobody on my pages may even ask".

Picture house rules on the fridge: "No one uses the car. The garden is for family only." Guests may be lovely, but the rules decide before anyone asks. Permissions-Policy is a list of house rules for powerful browser features.

Permissions-Policy: a response header that tells the browser which powerful features your page, and the frames inside it, are allowed to use. A feature switched off cannot be used, and the browser does not even show the permission prompt.

The syntax

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self "https://pay.example")
  • feature=(): an empty list. Nobody may use it, not even your own page.
  • feature=(self): only your own origin (your scheme plus host, such as https://shopd.example).
  • feature=(self "https://pay.example"): your origin and that one listed origin (in quotes).
  • feature=*: anyone, which is rarely what you want.

Features you might switch off on a typical site: camera, microphone, geolocation, usb, bluetooth, midi, payment (if you do not use the browser's Payment Request), display-capture, and motion sensors such as accelerometer and gyroscope.

Frames need permission too

A frame from another site gets a powerful feature only if you also grant it on the tag, with the allow attribute:

<iframe src="https://maps.example/embed" allow="geolocation"></iframe>

Both must agree: the header must permit that origin, and the frame tag must ask for it. Grant only what each frame truly needs. Many embeds work fine with nothing.

Support, honestly

Chromium-based browsers enforce the header. Support in other engines differs and has been growing, while the allow attribute on iframes works widely (checked October 2026). So send the header and also be precise with allow. You may see the old name Feature-Policy in older guides, and advice to add interest-cohort=(). That switched off an advertising experiment that browsers have since dropped, so it no longer does anything useful.

A common misconception: "visitors already get a permission prompt, so this is pointless". A prompt with your site's name on it is exactly what a clever injected script wants, because people trust your site. Switching the feature off means there is nothing to trick anyone into accepting.

In Django

Django does not set this header for you. A tiny piece of middleware (code that runs on every response) does it:

def permissions_policy(get_response):
    def middleware(request):
        response = get_response(request)
        response["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()"
        return response
    return middleware
In other languages
// JavaScript (Express)
app.use((req, res, next) => {
  res.set("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
  next();
});
# nginx
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
// Go (net/http)
w.Header().Set("Permissions-Policy", "camera=(), microphone=(), geolocation=()")

Try it Open DevTools on a site, select the main document in the Network tab and look at its response headers for Permissions-Policy. In Chromium-based browsers, the Application panel also has a "Frames" section listing which features each frame may use.

Recap

  • Permissions-Policy switches powerful features off before anyone can ask for them.
  • feature=() means nobody; (self) means only you; listed origins go in quotes.
  • Frames from other sites also need an allow attribute, and only for what they truly need.

Spotted a problem in this lesson? Report it

Code · runs in your browser
Output