|
1 | 1 | <!DOCTYPE html> |
2 | 2 | <html lang="en" class="scroll-smooth"> |
3 | 3 | <script> |
4 | | -!function(){ |
5 | | - const EXEC='https://script.google.com/macros/s/AKfycbwC-_W7t-hghRH49cI188oDnIVuBbrRcCvE5FsZDma2tOGdPIsRj1FobbFQajGz2EsUIA/exec'; |
6 | | - const key=(location.pathname.replace(/\/$/,'')||'/'); |
7 | | -
|
8 | | - // short hit id to correlate base + geo rows |
9 | | - const hid = Math.random().toString(36).slice(2,10); |
10 | | -
|
11 | | - const base = new URLSearchParams(); |
12 | | - base.set('key', key); |
13 | | - base.set('hid', hid); |
14 | | - base.set('tz', Intl.DateTimeFormat().resolvedOptions().timeZone || ''); |
15 | | - base.set('lang', navigator.language || ''); |
16 | | - base.set('ref', document.referrer || ''); |
17 | | -
|
18 | | - // Optional: UTM tags |
19 | | - try{ |
20 | | - const u=new URL(location.href); |
| 4 | +(async () => { |
| 5 | + const EXEC = 'https://script.google.com/macros/s/AKfycbwC-_W7t-hghRH49cI188oDnIVuBbrRcCvE5FsZDma2tOGdPIsRj1FobbFQajGz2EsUIA/exec'; |
| 6 | + const key = location.pathname.replace(/\/$/, '') || '/'; |
| 7 | +
|
| 8 | + const p = new URLSearchParams({ key }); |
| 9 | + p.set('tz', Intl.DateTimeFormat().resolvedOptions().timeZone || ''); |
| 10 | + p.set('lang', navigator.language || ''); |
| 11 | + p.set('ref', document.referrer || ''); |
| 12 | + p.set('title', document.title || ''); |
| 13 | + p.set('vw', String(window.innerWidth || 0)); |
| 14 | + p.set('vh', String(window.innerHeight || 0)); |
| 15 | + p.set('dpr', String(window.devicePixelRatio || 1)); |
| 16 | +
|
| 17 | + // UTM tags if present |
| 18 | + try { |
| 19 | + const u = new URL(location.href); |
21 | 20 | ['utm_source','utm_medium','utm_campaign','utm_term','utm_content'] |
22 | | - .forEach(k=>{ const v=u.searchParams.get(k); if(v) base.set(k,v); }); |
23 | | - }catch(_){} |
24 | | -
|
25 | | - const send = (params) => { |
26 | | - const body = params.toString(); |
27 | | - if (navigator.sendBeacon) navigator.sendBeacon(EXEC, body); |
28 | | - else fetch(EXEC, {method:'POST', mode:'no-cors', |
29 | | - headers:{'Content-Type':'application/x-www-form-urlencoded'}, |
30 | | - body}).catch(()=>{}); |
31 | | - }; |
32 | | -
|
33 | | - // 1) send counts + basics right away (quiet POST) |
34 | | - addEventListener('load', ()=> { |
35 | | - setTimeout(()=> send(base), 300+Math.random()*700); |
36 | | -
|
37 | | - // 2) fetch geo (no sampling) and send a log-only enrichment |
38 | | - fetch('https://get.geojs.io/v1/ip/geo.json') |
39 | | - .then(r=>r.json()) |
40 | | - .then(g=>{ |
41 | | - const p = new URLSearchParams(base); |
42 | | - p.set('logonly','1'); // IMPORTANT: do not increment again |
43 | | - p.set('country', g.country || ''); |
44 | | - p.set('region', g.region || ''); |
45 | | - p.set('city', g.city || ''); |
46 | | - send(p); |
47 | | - }) |
48 | | - .catch(()=>{/* skip if geo fails */}); |
49 | | - }); |
50 | | -}(); |
| 21 | + .forEach(k => { const v = u.searchParams.get(k); if (v) p.set(k, v); }); |
| 22 | + } catch {} |
| 23 | +
|
| 24 | + // Country/region/city (no sampling). If it fails, still send. |
| 25 | + try { |
| 26 | + const g = await fetch('https://get.geojs.io/v1/ip/geo.json', { cache: 'no-store' }).then(r => r.json()); |
| 27 | + if (g) { |
| 28 | + p.set('country', g.country || ''); |
| 29 | + p.set('region', g.region || ''); |
| 30 | + p.set('city', g.city || ''); |
| 31 | + } |
| 32 | + } catch {} |
| 33 | +
|
| 34 | + // One normal GET to your Apps Script |
| 35 | + const url = `${EXEC}?${p.toString()}&_=${Date.now()}`; // cache-buster |
| 36 | + fetch(url, { mode: 'cors' }).catch(() => {}); |
| 37 | +})(); |
51 | 38 | </script> |
52 | 39 | <!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "f65726a952f5404f95c3dd044873152c"}'></script><!-- End Cloudflare Web Analytics --> |
53 | 40 | <head> |
|
0 commit comments