Skip to main content

Landing Page

Landing Page

Overview

URL: https://getdrop.no
Purpose: Multi-language marketing landing page for Drop — fintech payment app
Target users: All residents in Norway/Scandinavia (not diaspora-only)

Architecture

  • Hosting: Cloudflare Pages
  • Zone ID: 0e4476892bfc1eaace41a80d6d060607
  • Stack: Static HTML + CSS (no build process)
  • Deployment: wrangler pages deploy via GitHub Actions (landing-deploy.yml)
  • Database: Cloudflare D1 (SQLite) for waitlist signups

File Structure

landing/
├── index.html              # Main entry point (Norwegian default)
├── locales/                # 12 language JSON files (nb, en, sv, da, fi, bs, sr, hr, de, tr, sq, pl)
├── functions/
│   └── api/waitlist.js     # CF Function — waitlist signup endpoint
├── _headers                # Security headers (CSP, HSTS, X-Frame-Options)
├── wrangler.toml           # CF Pages + D1 config
├── package.json            # Dependencies (wrangler only)
├── manifest.json           # PWA manifest
├── sw.js                   # Service worker
├── favicon.svg             # Drop logo favicon
└── pages/                  # Static sub-pages (send-penger, qr-betaling, priser, etc.)

Hero Design Decision (2026-04-22)

Problem: CEO feedback — landing page showed fake app demo mockup (SpareBank balance, fake transactions, "Mama Jasmina") instead of actual product information.

Solution: Replaced demo mockup with info-first corridor card showing:

  • Flow: Norge 🇳🇴 → 30+ land 🌐
  • Destination grid: Bosnia, Serbia, Croatia, Albania, Poland + 25 more
  • Key stats: 0.5% fee / <1 min transfer / BankID auth

Code change: Commit dfa0b3b3 on main
MC task: #8729
Files changed: landing/index.html (155 insertions, 110 deletions)

Visual proof:

  • Desktop: /tmp/drop-screenshots/getdropno-desktop-waited.png
  • Mobile: /tmp/drop-screenshots/getdropno-mobile-waited.png

Verification:

curl https://getdrop.no | grep -c 'ps-balance'           # 0 (removed)
curl https://getdrop.no | grep -c 'phone-screen'         # 0 (removed)
curl https://getdrop.no | grep -c 'SpareBank'            # 0 (removed)
curl https://getdrop.no | grep -c 'Mama Jasmina'         # 0 (removed)
curl https://getdrop.no | grep -c 'corridor-card'        # 3 (present)

Waitlist Flow

  1. User submits email via form at #cta section
  2. POST /api/waitlist → CF Function at functions/api/waitlist.js
  3. Validation: Email regex + honeypot field (website)
  4. Storage: CF D1 database (drop-waitlist, binding DB)
  5. Schema: waitlist_signups table (id, email, source, created_at)
  6. Response: JSON {ok: true, message: 'Registrert!'}

Admin access: GET /api/waitlist?key=<WAITLIST_ADMIN_KEY> returns all signups (rate-limited, 5 attempts per 15 min)

Internationalization (i18n)

Languages: 12 supported

CodeLanguageFile
nbNorsk (bokmål)locales/no.json
enEnglishlocales/en.json
svSvenskalocales/sv.json
daDansklocales/da.json
fiSuomilocales/fi.json
bsBosanskilocales/bs.json
srSrpskilocales/sr.json
hrHrvatskilocales/hr.json
deDeutschlocales/de.json
trTürkçelocales/tr.json
sqShqiplocales/sq.json
plPolskilocales/pl.json

Implementation: Language switcher dropdown in nav, preference stored in localStorage

Deployment

Method: GitHub Actions workflow (.github/workflows/landing-deploy.yml)

Trigger: Push to main with changes in landing/** path

Process:

  1. Checkout repo
  2. Setup Node.js 20
  3. Install dependencies (npm ci)
  4. Deploy via Wrangler: wrangler pages deploy . --project-name=$CF_LANDING_PROJECT_NAME --branch=main

Secrets required:

  • CLOUDFLARE_API_TOKEN (CF Global API Key)
  • CLOUDFLARE_ACCOUNT_ID
  • CF_LANDING_PROJECT_NAME (project name in CF Pages)

DNS:

  • getdrop.no → CF Pages (CNAME)
  • www.getdrop.no → CF Pages (CNAME)
  • app.getdrop.no → Azure Caddy reverse proxy (app backend)

Security Headers

File: _headers

X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-XSS-Protection: 1; mode=block
  • MC #8485 — CF Pages migration (completed)
  • MC #8537 — Waitlist PostgreSQL wire-up (completed)
  • MC #8729 — Info-first hero redesign (ready for review)
  • MC #8731 — Proveo validation (pending)
  • MC #8732 — Git config fix (completed)

Key Metrics

  • Total locales: 12 language files
  • Waitlist database: CF D1 SQLite (auto-created table)
  • Current signups: Query via admin endpoint
  • Deploy target: Cloudflare Pages (CDN-backed, global edge)

Future Improvements

  • Add A/B testing for hero variants
  • Integrate analytics (Plausible or CF Web Analytics)
  • Expand corridor card with real-time exchange rates
  • Add language auto-detection based on IP geolocation