If you’ve ever embedded a PDF, DOCX, or PPTX with Google Docs Viewer, you’ve probably hit the same wall everyone does: your Content Security Policy breaks it.
That’s not a bug. That’s CSP doing its job.
The annoying part is that Google Docs Viewer sits in an awkward middle ground. It’s convenient, familiar, and dead simple to drop into an <iframe>. But once you care about a tight CSP, third-party framing gets messy fast. You have to decide how much trust you want to hand to Google for a document-rendering feature that may not even be essential.
Here’s the practical comparison guide I wish more people wrote.
The basic problem
Google Docs Viewer is usually embedded like this:
<iframe
src="https://docs.google.com/gview?embedded=1&url=https://example.com/files/report.pdf"
width="100%"
height="700"
loading="lazy">
</iframe>
If your CSP has a restrictive frame-src, that embed won’t load unless https://docs.google.com is allowed.
At minimum, you’re looking at something like:
Content-Security-Policy: default-src 'self'; frame-src 'self' https://docs.google.com;
That’s the simplest answer. It’s also not always the best one.
If you want a refresher on directives like frame-src, default-src, and frame-ancestors, csp-guide.com is a good reference without a lot of fluff.
Option 1: Allow Google Docs Viewer directly
This is the common setup.
Example CSP
Content-Security-Policy:
default-src 'self';
frame-src 'self' https://docs.google.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
Pros
- Fastest path to shipping
- Works well for public documents
- No need to build your own document rendering stack
- Keeps your app code simple
Cons
- You’re trusting a third-party origin in
frame-src - Viewer availability depends on Google
- Some files render inconsistently
- Private or signed URLs can be painful
- You get less control over UX and privacy
My opinion: this is acceptable for low-risk public content, especially brochures, whitepapers, manuals, and marketing docs. I would not use it casually for anything sensitive, internal, or access-controlled.
Option 2: Allow broad Google origins “just in case”
I still see teams do this:
Content-Security-Policy:
default-src 'self';
frame-src 'self' https://docs.google.com https://*.google.com https://*.gstatic.com;
Usually this happens after a few rounds of “it still doesn’t work in staging” and someone starts adding domains until the embed stops complaining.
Pros
- Lower chance of breakage from undocumented Google dependencies
- Faster debugging when you’re under deadline pressure
Cons
- Sloppy trust boundary
- Harder to audit later
- Easier to normalize overbroad CSP exceptions
- Usually unnecessary
I don’t recommend this unless you’ve actually observed a required dependency and documented why it exists. CSP exceptions have a way of becoming permanent. Temporary allowances almost never get cleaned up.
Option 3: Use a dedicated document route and isolate the policy
This is my preferred compromise when a product really wants Google Docs Viewer.
Instead of allowing docs.google.com across your whole application, serve the viewer from a dedicated route with a narrower purpose and a route-specific CSP.
For example:
/docs/viewer/:id→ page that only hosts the iframe- Main app pages keep a stricter CSP
- Viewer page gets a targeted
frame-src https://docs.google.com
Example route-specific CSP
For the rest of the app:
Content-Security-Policy:
default-src 'self';
frame-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
For /docs/viewer/:id:
Content-Security-Policy:
default-src 'self';
frame-src https://docs.google.com;
script-src 'self';
style-src 'self';
img-src 'self' data:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
Pros
- Limits third-party framing to one page
- Easier to reason about risk
- Cleaner security review
- Better than weakening the whole app
Cons
- More app and infrastructure work
- Requires per-route header support
- Still depends on Google
This is the version I’d defend in a security review. If you need the feature, isolate it.
Option 4: Don’t use Google Docs Viewer at all
Sometimes the best CSP for Google Docs Viewer is no Google Docs Viewer.
Alternatives include:
- Native browser PDF rendering
- Self-hosted PDF.js
- Server-side document conversion
- Download-only flow
Pros
- Stronger privacy story
- Tighter CSP
- More predictable availability
- Better control over UI and access checks
Cons
- More engineering effort
- Non-PDF formats are harder
- Conversion pipelines can get ugly
For PDFs, I’d seriously question why Google Docs Viewer is needed in 2026. Modern browsers already do a decent job. For Office docs, the calculus is different, but I’d still ask whether preview is truly required.
What not to change
A common mistake is loosening unrelated directives because the viewer doesn’t load.
Google Docs Viewer in an iframe usually affects frame-src. It does not mean you need to weaken:
script-srcstyle-srcobject-srcbase-uriform-action
If your app currently has a decent baseline, keep it.
For example, this real-world CSP from HeaderTest is a good example of staying explicit and tight in the places that matter:
content-security-policy: default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com; script-src 'self' 'nonce-MmQ2ODQ5Y2YtMzNhZC00MGQ3LWFlNDItNTQ4OTdlNzU0NGM0' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com; style-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://*.cookiebot.com https://consent.cookiebot.com; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.headertest.com https://tallycdn.com https://or.headertest.com wss://or.headertest.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com; frame-src 'self' https://consentcdn.cookiebot.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
Notice what’s happening there:
frame-srcis specificobject-src 'none'stays locked downbase-uri 'self'andform-action 'self'are explicit- The policy doesn’t randomly broaden everything for one embed
That’s the mindset you want.
Recommended CSP patterns
Minimal change for Google Docs Viewer
Content-Security-Policy:
default-src 'self';
frame-src 'self' https://docs.google.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
Use this if:
- documents are public
- the route is low risk
- you need the feature quickly
Safer isolated route approach
Content-Security-Policy:
default-src 'self';
frame-src https://docs.google.com;
script-src 'self';
style-src 'self';
img-src 'self' data:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
Use this if:
- you can set headers per route
- you want tighter blast-radius control
- security review matters
Strict no-third-party viewer approach
Content-Security-Policy:
default-src 'self';
frame-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
Use this if:
- you render documents yourself
- you only support direct download
- you want the simplest trust model
Extra gotchas
frame-src vs child-src
If you’re supporting older CSP setups, you may still see child-src. Modern policies should prefer frame-src for frames. Don’t cargo-cult both unless you have a compatibility reason.
frame-ancestors is unrelated
frame-ancestors controls who can embed your page. It does not grant permission for you to embed Google Docs Viewer. I still see this confused in production configs.
Signed URLs may fail
If your documents are behind expiring URLs, Google’s fetch behavior can cause flaky previews. A URL that works fine in a browser tab may fail when passed to gview.
Privacy and compliance questions
When you send a document URL to a Google-hosted viewer, that choice has policy implications. Your legal or compliance team may care more than engineering does. Fair warning.
My take
If I had to rank the options:
- Self-host or native rendering for anything serious
- Isolated viewer route if Google Docs Viewer is a product requirement
- Direct
frame-src https://docs.google.comfor low-risk public content - Broad Google allowlists only when you have hard evidence and no better option
The real trap isn’t using Google Docs Viewer. The real trap is using it and then quietly weakening your CSP across the entire app because “it was easier.”
That trade is almost never worth it.