DateSpots.NYC is a curated site for date spots in and around New York City. It's free, and it's built from a few pieces that fit together: Google Sheets, Cloudflare Workers, WordPress, and the Google Maps API. Here's how it works and why some of those choices matter.

Google Sheets

The backbone of the data is Google Sheets. There's a master index sheet that lists all the category sheets (Italian, wine bars, brunch, Westchester, and so on). Each category is its own sheet. In total there are 49-plus sheets and over 1,400 spots. Curators add and edit rows: name, neighborhood, type, budget, vibe, hours, a short blurb, and often a link to directions. No code required. When you view a category page on the site, WordPress plugins (FlexTable and GSWPTS) fetch that sheet and render it as a table. When you use Plan a Date or the Date Quiz, a Cloudflare Worker reads from a copy of that same data stored in Workers KV, which was ingested from the same sheets. So Sheets is the single source of truth. Update a sheet, refresh the worker's data pipeline, and both the static category tables and the interactive date planner see the new data.

Google Maps API

The Maps API is not used in real time on the site. It's used in batch scripts that curators (or I) run periodically. Those scripts take a list of venue names and maybe a city hint, call the Places Text Search API to find a place, then Place Details to get the official shareable URL (the maps.google.com link that opens in Google Maps or Apple Maps). We write those URLs back into the sheets. There's also a script that checks business status so we can flag or remove closed venues. So the API is for enriching and maintaining the data, not for serving live map requests. That keeps the site simple and keeps API usage predictable.

Cloudflare Workers

There are two workers in front of the site.

The first one (gsheet cache) sits in front of WordPress. When a page loads a table from a Google Sheet, the browser sends a request to WordPress's admin-ajax.php. The worker intercepts that request. If it has a cached response (edge cache or Workers KV), it returns it immediately and never hits WordPress or Google. If not, it forwards to WordPress, gets the response, strips out any sensitive stuff (sheet URLs, spreadsheet IDs) so we don't leak that to the client, then caches the sanitized response and serves it. So the heavy, repeated traffic (every category page load) is served from the edge. WordPress and the Sheets API are only hit on a cache miss. That's why the CDN is so important: without it, every table view would hit the origin. At peak we've seen around 200 requests per second. The origin would not hold up. With the worker and Cloudflare's edge cache, most requests are answered in sub-millisecond time from a colo near the user. The origin stays healthy and the site stays fast.

The second worker (datespots curator) is the date planner engine. It reads the same venue data from a master index of sheets, fetches each category sheet as CSV, normalizes the columns into one schema, and stores everything in Workers KV. That ingestion runs in three chunks to stay under Cloudflare's subrequest limits. Once the data is in KV, the curator exposes APIs: one that takes vibe, neighborhood, budget, time of day, duration (and optionally cuisine) and returns a curated one to three stop itinerary. Another that generates a short narrative connecting those stops using Workers AI. And one that returns a "Date of the Week," a rotating three stop plan cached per week. The Plan a Date and Date Quiz pages on the site are static HTML forms embedded in WordPress; they call this worker's APIs and render the results. So the brains (filtering, scoring, day of week awareness, itinerary assembly) live in the worker; WordPress is just the host for the pages and the UI.

Curators and date planners

Curators are the people who maintain the sheets. They add venues, update hours, fix typos, and keep the lists honest. The date planners are the features that use that data to suggest an itinerary: Plan a Date (pick vibe, location, budget, get a plan), the Date Compatibility Quiz (both partners answer a few questions, get a compatibility score and a shared plan), and Date of the Week (a single curated three stop date that rotates weekly). So curators feed the data; the planner engine and the front ends turn it into a useful experience.

WordPress

WordPress runs the public site. It serves the homepage, the category pages, the about and contact pages, and the pages that embed Plan a Date, the Date Quiz, and the Date of the Week widget. The table plugins (FlexTable, GSWPTS) are what pull sheet data into the category pages; their requests go through the gsheet cache worker, so WordPress never talks to Google directly for those. The interactive tools are Custom HTML blocks that point at the curator worker. So WordPress is the face and the content framework. The dynamic, data heavy work is done at the edge by the workers.

Why the CDN is so important

Already touched on this above. In short: traffic hits Cloudflare first. The worker can serve cached table data and cached curator responses from the edge or from KV. That means the origin (WordPress) and the data sources (Google Sheets) are not hammered on every page load or every "plan my date" click. For a free site that can spike when something gets shared, that's the difference between the site staying up and the origin falling over. The CDN also gives us one place to handle SSL, caching headers, and a bit of DDoS protection. So the CDN isn't optional; it's what makes the architecture viable.

Why the site is free (and probably will stay that way)

DateSpots started from a different project: a book on modern dating. The chapter on finding great date spots felt like something that could matter to more people if it wasn't locked in a book. So the idea became a site that anyone in NYC could use for free. There are more important things than money and vanity. Helping people find a good place for a date, or a memorable experience with someone they care about, is one of them. I don't plan to put up a paywall or hide the best spots behind a signup. The site will probably stay free. The architecture (Sheets, workers, CDN, WordPress) is built so we can keep it that way without burning out the origin or the curators.