Skip to content

How It Works

Technical overview of GoPayLocal's architecture and request flow.

GoPayLocal is built on Cloudflare’s edge network to deliver PPP discounts with minimal latency and zero impact on your page load.

When a visitor loads your page with the GoPayLocal script, here is what happens:

  1. Browser loads the script

    The <script> tag loads asynchronously (~5KB, 1.5KB gzipped). It does not block page rendering.

  2. Cloudflare Worker detects the country

    The script makes a request to api.gopaylocal.com. Because the API runs on Cloudflare Workers, the visitor’s country is available instantly from the CF-IPCountry header — no external geolocation API needed.

    Cost: $0. Latency: 0ms (it’s a request header, not a lookup).

  3. PPP tier and discount lookup from KV

    The Worker reads the campaign configuration and parity group data from Cloudflare KV (edge key-value store). This lookup happens at the nearest edge location to the visitor.

    Latency: < 10ms (data is cached at 300+ edge locations worldwide).

  4. VPN/proxy check

    The Worker checks the visitor’s IP against known VPN and proxy IP ranges using ASN (Autonomous System Number) data and open-source IP lists stored in a dedicated KV namespace.

    If a VPN is detected, the discount is withheld to prevent abuse.

  5. Personalized response

    The Worker returns a JSON response containing:

    • Whether to show a discount (show: true/false)
    • Country code and name
    • Discount percentage
    • Coupon code (if using coupon-based delivery)
    • Local currency code, symbol, and FX rate
    • Banner configuration (position, colors, message template)
  6. Banner renders in Shadow DOM

    The script creates a Shadow DOM element and renders the discount banner inside it. Shadow DOM ensures the banner’s styles are completely isolated from your site — no CSS conflicts, no layout shifts.

┌─────────────────────────────────────────────────────┐
│ Visitor's Browser │
│ │
│ ┌──────────┐ ┌────────────────────────────────┐ │
│ │ Your App │ │ GoPayLocal Banner (Shadow DOM) │ │
│ └──────────┘ └────────────────────────────────┘ │
│ │ ▲ │
│ │ │ Render │
│ ▼ │ │
│ ┌─────────────────────────────────┐ │
│ │ Banner Script (5KB / 1.5KB gz) │ │
│ └──────────┬──────────────────────┘ │
└─────────────┼───────────────────────────────────────┘
│ fetch (async)
┌─────────────────────────────────────────────────────┐
│ Cloudflare Edge (nearest PoP) │
│ │
│ ┌──────────────────┐ ┌────────────────────┐ │
│ │ Hono API Worker │───▶│ Cloudflare KV │ │
│ │ │ │ - Campaign config │ │
│ │ 1. Read country │ │ - Parity groups │ │
│ │ (CF header) │ │ - VPN IP lists │ │
│ │ 2. Lookup PPP │ └────────────────────┘ │
│ │ 3. Check VPN │ │
│ │ 4. Return config│ ┌────────────────────┐ │
│ │ 5. Log analytics│───▶│ Analytics Engine │ │
│ └──────────────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────┘

GoPayLocal uses multiple layers of caching for performance:

LayerWhat’s CachedTTL
Cloudflare KVCampaign configs, parity groups, FX rates5 minutes
Browser sessionStoragePPP response per API key5 minutes
Cloudflare CDNBanner script file1 hour

The sessionStorage cache means repeat page views within the same session never make an additional API call.

Events (impressions, clicks, copies, dismissals) are sent via navigator.sendBeacon() to the analytics endpoint. This ensures events are captured even when the user navigates away — without blocking page unload.

Events flow into Cloudflare’s Workers Analytics Engine, which provides real-time aggregation without a separate analytics database.

  • Shadow DOM isolation — The banner cannot access your page’s DOM or cookies
  • XSS prevention — All dynamic content in the banner is inserted via textContent or programmatic DOM APIs, never raw HTML
  • VPN detection — ASN + IP list based, upgradeable to paid services for higher accuracy
  • API key scoping — Public keys (gpl_pk_*) can only read banner configs; secret keys (gpl_sk_*) are required for management APIs
  • Domain allowlisting — Campaigns can be restricted to specific domains