A fast, privacy-focused Progressive Web App (PWA) for searching images on JW.org using Google Custom Search Engine.
- Privacy-first: No personal data collection, no analytics, no tracking cookies
- PWA support: Installable on mobile devices, works offline
- Accessible: WCAG 2.1 AA compliant with full keyboard navigation and screen reader support
- Fast: Cache-first loading for static assets, optimized for performance
- Secure: API credentials stored server-side only, never exposed to the browser
Before deploying this application, you need to set up Google Custom Search Engine:
- Go to Google Programmable Search Engine
- Click "Add" to create a new search engine
- Configure the following settings:
- Sites to search: Add
jw.organd*.jw.org - Search the entire web: Turn OFF
- Enable image search: Turn ON (important!)
- Sites to search: Add
- Save your search engine
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the "Custom Search JSON API":
- Navigate to "APIs & Services" > "Library"
- Search for "Custom Search JSON API"
- Click "Enable"
- In Google Cloud Console, go to "APIs & Services" > "Credentials"
- Click "Create Credentials" > "API Key"
- Important: Restrict the API key:
- Click "Edit API Key"
- Under "API restrictions", select "Restrict key"
- Choose "Custom Search JSON API" from the dropdown
- Save
- Copy your API key (you'll need this for Vercel)
- Go back to your Programmable Search Engine
- Find your search engine in the list
- Copy the "Search engine ID" (looks like:
xxxxxxxxx:xxxxxxxxxxxxx)
Create a .env.local file for local development (this file is git-ignored):
# .env.local
GOOGLE_CSE_ID=your_cse_id_here
GOOGLE_API_KEY=your_api_key_hereNever commit real credentials to git! The .env.example file is provided as a template.
npm install -g vercelvercel loginvercel devThe app will be available at http://localhost:3000 (or the port shown in your terminal).
vercel link# Production environment
vercel env add GOOGLE_CSE_ID production
vercel env add GOOGLE_API_KEY production
# Preview environment (if needed)
vercel env add GOOGLE_CSE_ID preview
vercel env add GOOGLE_API_KEY preview
# Development environment (if needed)
vercel env add GOOGLE_CSE_ID development
vercel env add GOOGLE_API_KEY developmentOr set them via the Vercel dashboard:
- Go to your project in Vercel
- Navigate to "Settings" > "Environment Variables"
- Add
GOOGLE_CSE_IDandGOOGLE_API_KEY
# Deploy to preview
vercel
# Deploy to production
vercel --prodBefore going live, update the following files to replace YOUR_DOMAIN with your actual domain:
robots.txtsitemap.xmlindex.html(meta tags)terms-of-use.html(if needed)cookie-policy.html(if needed)privacy-policy.html(if needed)
/
├── api/
│ └── search.js # Vercel serverless function (secure proxy)
├── icons/
│ ├── icon-192.svg # PWA icon (192x192)
│ └── icon-512.svg # PWA icon (512x512)
├── css/
│ └── style.css # All styles with CSS custom properties
├── js/
│ ├── app.js # Main application entry point
│ ├── search.js # Search API client
│ ├── masonry.js # Masonry layout & infinite scroll
│ ├── lightbox.js # Image preview modal
│ └── cookies.js # Cookie consent management
├── index.html # Main page
├── terms-of-use.html # Legal page
├── cookie-policy.html # Legal page
├── privacy-policy.html # Legal page
├── manifest.json # PWA manifest
├── service-worker.js # PWA offline support
├── vercel.json # Vercel configuration & security headers
├── robots.txt # Search engine instructions
├── sitemap.xml # SEO sitemap
├── .env.example # Environment variables template
└── README.md # This file
- HTML, CSS, and JavaScript files served as static assets
- No server-side rendering
- All client-side functionality via vanilla JavaScript
- Single serverless function at
/api/search.js - Runs on Vercel Edge Runtime for low latency
- Handles all communication with Google's API
- Credentials exist only in this function's environment
- User enters search query in browser
- Browser calls
/api/search?q=...(same origin) - Serverless function reads credentials from
process.env - Function calls Google CSE API with credentials
- Function normalizes response and returns to browser
- Browser displays results
Key Security Point: The browser never receives or sees the API credentials.
The free tier of Google Custom Search Engine allows:
- 100 queries per day
When the quota is exceeded, the API returns a 403 error. The app displays a friendly message to users.
To increase your quota, you need to set up billing in Google Cloud Console.
This app is built with accessibility in mind:
- Skip link: Jump to main content
- Focus indicators: Visible focus rings on all interactive elements
- Keyboard navigation: Full keyboard support for all features
- Screen reader support: Proper ARIA labels and live regions
- Color contrast: All text passes WCAG AA (4.5:1 minimum)
- Reduced motion: Respects
prefers-reduced-motionsetting - Touch targets: All buttons are at least 44x44 CSS pixels
- Installable: Can be added to home screen on mobile devices
- Offline support: Static assets cached for offline viewing
- Theme color: Matches app chrome to brand colors
- Standalone display: Opens without browser UI when installed
The app uses the "Lavender Dusk" color palette:
| Variable | Value | Usage |
|---|---|---|
--colour-bg |
#F4F2F9 | Page background |
--colour-surface |
#FFFFFF | Card backgrounds |
--colour-primary |
#7B5EA7 | Buttons, links, focus |
--colour-primary-dark |
#5C4280 | Hover states |
--colour-text |
#2D2040 | Primary text |
--colour-border |
#C5B8E0 | Borders |
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
This project is provided as-is for educational and personal use.
This is an independent tool. Not affiliated with jw.org, the Watchtower Bible and Tract Society of Pennsylvania, or Google LLC.
All images remain the property of their respective owners. This application does not host, copy, or redistribute any images.
For questions or issues, please contact: contact@example.com