diff --git a/README.md b/README.md
index b16693d..9c29f1c 100644
--- a/README.md
+++ b/README.md
@@ -27,4 +27,4 @@ VITE_ADSENSE_CLIENT=ca-pub-XXXXXXXXXXXXXXXX
VITE_ADSENSE_SLOT=XXXXXXXXXX
```
-Add the same values to a local `.env.local` file when testing. The AdSense script is loaded globally, while ad slots render only when both values are present. Use the exact publisher and slot IDs from AdSense; do not use guessed or test IDs in production.
+Add the same values to a local `.env.local` file when testing. For Vercel, open **Project Settings → Environment Variables**, add both variables for **Production**, **Preview**, and **Development** as needed, then redeploy. Because these are `VITE_` variables, Vite injects them at build time; changing them requires a new deployment. The AdSense script and ad slots render only when both values are present. Use the exact publisher and slot IDs from AdSense; do not use guessed or test IDs in production.
diff --git a/index.html b/index.html
index 1a80f6b..4df03aa 100644
--- a/index.html
+++ b/index.html
@@ -33,7 +33,6 @@
-
diff --git a/public/_headers b/public/_headers
index fd3b74e..3d55d4b 100644
--- a/public/_headers
+++ b/public/_headers
@@ -3,4 +3,4 @@
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
- Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google https://media.ethicalads.io blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';
+ Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com https://www.google.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';
diff --git a/src/components/AdSlot.tsx b/src/components/AdSlot.tsx
index 6f27676..e02f6c4 100644
--- a/src/components/AdSlot.tsx
+++ b/src/components/AdSlot.tsx
@@ -26,10 +26,18 @@ export const AdSlot: React.FC = ({ placement, className = '' }) =>
useEffect(() => {
if (!canRenderAd || !adRef.current || typeof window === 'undefined') return;
- try {
- (window.adsbygoogle = window.adsbygoogle || []).push({});
- } catch {
- // Ad blockers and unapproved accounts can prevent the ad request.
+ const pushAd = () => {
+ try {
+ (window.adsbygoogle = window.adsbygoogle || []).push({});
+ } catch {
+ return;
+ }
+ };
+
+ if (document.querySelector('script[data-adsense-loader]')) {
+ pushAd();
+ } else {
+ window.setTimeout(pushAd, 250);
}
}, [canRenderAd]);
diff --git a/src/main.tsx b/src/main.tsx
index 5252e9d..fe3c053 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -3,6 +3,16 @@ import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.tsx';
+const adsenseClient = import.meta.env.VITE_ADSENSE_CLIENT;
+if (adsenseClient && typeof document !== 'undefined' && !document.querySelector('script[data-adsense-loader]')) {
+ const script = document.createElement('script');
+ script.async = true;
+ script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(adsenseClient)}`;
+ script.crossOrigin = 'anonymous';
+ script.dataset.adsenseLoader = 'true';
+ document.head.appendChild(script);
+}
+
createRoot(document.getElementById('root')!).render(
diff --git a/vercel.json b/vercel.json
index 6e48b2a..1ff9bed 100644
--- a/vercel.json
+++ b/vercel.json
@@ -21,7 +21,7 @@
},
{
"key": "Content-Security-Policy-Report-Only",
- "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://media.ethicalads.io blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob:; connect-src 'self' https: blob: data:; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';"
+ "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com https://www.google.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';"
}
]
}