Content Security Policy (CSP) Configuration
Content Security Policy (CSP) is a security feature that helps prevent cross-site scripting (XSS) attacks. When integrating FramePay, you need to configure your CSP to allow the necessary domains.
Overview
FramePay loads payment fields via secure iframes and requires specific CSP directives to function properly. This guide covers:
- 🔒 Required CSP directives
- 🌐 Allowed domains
- ⚙️ Configuration methods
- 🎯 Best practices
Required CSP Directives
Minimum Configuration
To use FramePay with card payments only, include these directives:
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
connect-src 'self' framepay.payments.ai *.payments.ai;
style-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;
img-src 'self' data: framepay.payments.ai;
font-src 'self';
">
Full Configuration (with Digital Wallets)
If you're using Apple Pay, Google Pay, or PayPal, add their domains:
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline'
framepay.payments.ai
*.paypal.com
*.google.com
*.cdn-apple.com;
connect-src 'self'
framepay.payments.ai
*.payments.ai
*.paypal.com
*.google.com
*.apple.com;
style-src 'self' 'unsafe-inline'
framepay.payments.ai
fonts.googleapis.com;
frame-src 'self'
framepay.payments.ai
*.paypal.com
*.google.com;
img-src 'self' data:
framepay.payments.ai
*.paypal.com
*.google.com;
font-src 'self'
fonts.gstatic.com;
">
Configuration Methods
Method 1: HTML Meta Tag
Add the CSP meta tag in your HTML <head> section:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com;
connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com;
style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com;
frame-src 'self' framepay.payments.ai *.paypal.com *.google.com;
img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com;
font-src 'self' fonts.gstatic.com;
">
<title>Checkout</title>
</head>
<body>
<!-- Your content here -->
</body>
</html>
Method 2: HTTP Header (Recommended)
Configure CSP via HTTP headers on your server. This is the recommended approach for production.
Node.js/Express
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; " +
"connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; " +
"style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; " +
"frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; " +
"img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; " +
"font-src 'self' fonts.gstatic.com;"
);
next();
});
Nginx
location / {
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; font-src 'self' fonts.gstatic.com;";
}
Apache
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; font-src 'self' fonts.gstatic.com;"
</IfModule>
Next.js
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com",
"connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com",
"style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com",
"frame-src 'self' framepay.payments.ai *.paypal.com *.google.com",
"img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com",
"font-src 'self' fonts.gstatic.com"
].join('; ')
}
]
}
]
}
}
CSP Directive Breakdown
default-src 'self'
Sets the default policy for all content types. 'self' allows content only from your own domain.
script-src
Controls which JavaScript sources are allowed:
'self'- Your own domain'unsafe-inline'- Required for FramePay inline scriptsframepay.payments.ai- FramePay CDN*.paypal.com- PayPal SDK (if using PayPal)*.google.com- Google Pay SDK (if using Google Pay)*.cdn-apple.com- Apple Pay SDK (if using Apple Pay)
⚠️ Security Note:
'unsafe-inline'reduces CSP protection. For production, consider using nonces for better security.
connect-src
Controls which domains can be contacted via XHR, WebSocket, or EventSource:
'self'- Your own domainframepay.payments.ai- FramePay API*.payments.ai- Payments AI API*.paypal.com- PayPal API*.google.com- Google Pay API
style-src
Controls stylesheet sources:
'self'- Your own stylesheets'unsafe-inline'- Required for inline stylesframepay.payments.ai- FramePay CSSfonts.googleapis.com- Google Fonts (if used)
frame-src
Controls which sources can be loaded in iframes (crucial for FramePay):
'self'- Your own domainframepay.payments.ai- FramePay payment fields*.paypal.com- PayPal iframe*.google.com- Google Pay iframe
img-src
Controls image sources:
'self'- Your own imagesdata:- Required for data URIs (card brand icons)framepay.payments.ai- FramePay images*.paypal.com- PayPal logos*.google.com- Google Pay logos
font-src
Controls font sources:
'self'- Your own fontsfonts.gstatic.com- Google Fonts (if used)
Payment Method Specific Configuration
Card Payments Only
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
connect-src 'self' framepay.payments.ai *.payments.ai;
style-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;
img-src 'self' data: framepay.payments.ai;
">
Apple Pay
Add these domains for Apple Pay:
script-src: *.cdn-apple.com
connect-src: *.apple.com
Google Pay
Add these domains for Google Pay:
script-src: *.google.com
connect-src: *.google.com
frame-src: *.google.com
img-src: *.google.com
PayPal
Add these domains for PayPal:
script-src: *.paypal.com
connect-src: *.paypal.com
frame-src: *.paypal.com
img-src: *.paypal.com
Using Nonces (Production)
For better security, use nonces instead of 'unsafe-inline':
Backend (Node.js/Express)
const crypto = require('crypto');
app.use((req, res, next) => {
// Generate nonce for this request
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader(
'Content-Security-Policy',
`default-src 'self'; ` +
`script-src 'self' 'nonce-${nonce}' framepay.payments.ai; ` +
`style-src 'self' 'nonce-${nonce}' framepay.payments.ai;`
);
next();
});
Frontend
<!-- Use the nonce in your script tags -->
<script nonce="<%= nonce %>">
Framepay.initialize({
publishableKey: 'pk_sandbox_xxx',
// ... config
});
</script>
Testing CSP Configuration
Browser Console
Open your browser's developer console (F12) and look for CSP violations:
Refused to load the script 'https://example.com/script.js' because it
violates the following Content Security Policy directive...
CSP Report Mode
Test your CSP without blocking resources using Content-Security-Policy-Report-Only:
<meta http-equiv="Content-Security-Policy-Report-Only" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
report-uri /csp-violation-report-endpoint;
">
This will report violations without blocking them, allowing you to test safely.
Online Tools
Use these tools to validate your CSP:
- CSP Evaluator - Google's CSP validation tool
- CSP Scanner - Comprehensive CSP analysis
Common Issues
Issue: FramePay not loading
Symptom: FramePay fields don't appear
Solution: Ensure script-src includes framepay.payments.ai and frame-src allows framepay.payments.ai
script-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;
Issue: Card brand icons not showing
Symptom: Visa, Mastercard logos don't appear
Solution: Add data: to img-src:
img-src 'self' data: framepay.payments.ai;
Issue: Wallet buttons not working
Symptom: Apple Pay/Google Pay/PayPal buttons don't respond
Solution: Add wallet provider domains to all relevant directives:
script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com;
connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com;
frame-src 'self' framepay.payments.ai *.paypal.com *.google.com;
Issue: HTTPS mixed content
Symptom: Console shows mixed content warnings
Solution: Ensure your page is served over HTTPS in production. CSP cannot fix HTTP served over HTTPS.
Best Practices
✅ Do
- Use HTTP headers over meta tags when possible
- Start with
Content-Security-Policy-Report-Onlyfor testing - Be as restrictive as possible while allowing necessary domains
- Use nonces or hashes instead of
'unsafe-inline'in production - Document your CSP configuration
- Monitor CSP violation reports
❌ Don't
- Use
'unsafe-eval'- it's not required for FramePay - Allow
*wildcards - they defeat the purpose of CSP - Forget to test on all payment methods you support
- Mix HTTP and HTTPS content
- Skip CSP validation in staging environments
Environment-Specific Configuration
Development
Content-Security-Policy-Report-Only: ...
Use report-only mode to identify issues without breaking functionality.
Staging
Content-Security-Policy: ...
Enforce CSP but with more permissive settings for testing.
Production
Content-Security-Policy: ... (strict configuration)
Use the strictest possible CSP with nonces and minimal wildcards.
Additional Security Headers
Consider adding these headers alongside CSP:
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Resources
- MDN: Content Security Policy
- CSP Quick Reference
- OWASP: Content Security Policy Cheat Sheet
- Google: CSP Evaluator
Next Steps
- 📖 Client-Side Integration - Set up FramePay on your frontend
- 🔄 Payment Flows - Understand payment processing
- 📚 Complete Example - See it all working together