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 ashttps://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 middlewareIn 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
allowattribute, and only for what they truly need.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.