tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#ten-years-one-developer')" >Ten years, one developer
Every line of Coworkations is mine: the product, the design, the data, the infrastructure and the emails. Over ten years and more than 2,200 commits it has been through a few lives:
2016: the first version, on Django, Bootstrap and jQuery, hosted on Heroku and seeded with Hacker Paradise's trips: retreats, trips, prices in several currencies, maps and itineraries.
2017: the busiest year. Reviews, Facebook review imports, calendar feeds, structured data and sitemaps, share images, alternatives pages, a Twitter bot, and the first scrapers. It came out of beta the following May.
2019: follows and saved searches, magic-link sign-in, Vue, and a first go at making it pay.
2023: a rebuild on Django 4.2, Tailwind and Vue 3, with full-text search, readable search URLs, screenshot share cards, sign-up for retreat owners and social features, then a return to Product Hunt.
2024 and 2025: badges and embeds, reviews from Google, Trustpilot and Facebook, MapLibre maps, and an onboarding checklist for owners.
2026: dark mode, globes, passkeys, AI that keeps trips current and translates reviews, trends, and photo and video galleries.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#every-retreat-compared')" >Every retreat, compared
Each retreat gets a page with what's included, prices, group size, reviews, alumni, every trip it's running, and similar retreats, so you can weigh one against another without opening a dozen tabs. Readers get exclusive coupon codes for some retreats, right on the page.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#where-theyve-been-on-a-globe')" >Where they've been, on a globe
A WebGL globe plots every trip a retreat has run, with arcs from one stop to the next, colored by past, now and upcoming. It fills the hero of traveler profiles too, with a 2D toggle.
Retreats embed it on their own sites, filtered to this year or next, and it rolls over by itself at New Year, so nobody has to remember to update it. Embeds follow the host site's theme rather than the visitor's, so a light site never gets a dark globe.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#search-that-reads-like-a-sentence')" >Search that reads like a sentence
Filter by price (in your own currency), length, rating, activities, region and group size, on a map or a list. Results page like Airbnb's, with the map showing just that page's trips.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#every-search-is-a-landing-page')" >Every search is a landing page
Every filter combination gets a readable title and URL, so "surf retreats in Asia" becomes a page of its own, with its own share card. Searches are saved as they're used, and the sitemap lists continents, countries and retreats first, then searches by how often people make them, so the pages people actually want are the ones search engines find.
Renaming or deleting a retreat or trip creates a permanent redirect by itself, so ten years of links still work. Retreats and trips carry schema.org structured data, and the site can be searched straight from the browser's address bar.
"Alternatives" pages, there since 2017, answer the search people make once they've found one retreat: what else is like it?
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#trips-you-can-actually-book')" >Trips you can actually book
Every trip has its dates, weekly and monthly prices, and what's nearby, next and similar.
Keeping 2,500 trips current by hand isn't possible for one person. From 2017 I wrote a scraper for each of the big retreats' sites, and kept them running for years. Now AI does the legwork: it reads each retreat's site with web search and a strict schema, and pulls out places, dates and room prices. It goes back to the retreats whose listings are oldest first, so nothing sits out of date for long.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#reviews-from-everywhere')" >Reviews from everywhere
Reviews are the best signal of what a retreat is really like, but they're scattered. Coworkations pulls them in from Google, Trustpilot and Facebook, with replies and photos. Each review is matched to the trip it's about by the dates it mentions, and owners' own reviews and spam are filtered out.
Reviews written in other languages are shown in English, with a link back to the original, and only the parts that aren't in English get translated. That runs on Llama on Cloudflare's Workers AI, within its free daily allowance. You can filter a retreat's reviews by the topics they mention most, and by rating, date or detail.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#photos-and-video-that-look-after-themselves')" >Photos and video that look after themselves
Retreat galleries fill themselves from each retreat's own site, and owners can upload more. Near-duplicates are caught by image fingerprints, screenshots of terms and other images that are mostly text are left out, and videos are shrunk with ffmpeg, with copies in another format or size spotted by comparing their first frames. Short silent loops play behind a retreat's title, unless you've asked your browser for less motion.
Places get photos and short looping clips from Nomads, through its MCP server, on a budget of calls per page so a busy page never waits on it. They're copied to R2 and cached apart from the rest, so a deploy never loses them.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#built-for-the-people-who-run-retreats')" >Built for the people who run retreats
Owners sign in with an email on their retreat's domain and their retreat is theirs, with no verification back and forth. They can invite co-managers, and work through a checklist that walks them from creating their page and listing their trips to inviting alumni to review them and embedding their badges. A backlink checker visits each retreat's site to see who links back, and retreats that go quiet get a nudge every couple of months to add their new trips.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#a-kit-for-retreat-owners')" >A kit for retreat owners
Retreats get SVG rating badges in light, neutral and dark, follow and review badges, count and score widgets, and a review wall with a live builder, all copy-paste. They show off their reviews on their own sites, and every badge links back here, so the retreats that do well on Coworkations help it grow.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#a-community-not-just-a-directory')" >A community, not just a directory
Travelers get profiles with a bio, their socials and a globe of where they've been. Profiles show "crossings", the other people who were on the same trips as you, whether as participants or facilitators. You can follow retreats, trips and people, and friends are the people who follow each other. Trips you add to your profile come as a calendar feed, and profiles can be private, with your data a click away to download.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#where-nomads-are-heading')" >Where nomads are heading
Trends ranks the fastest-growing cities and countries by comparing the last three years with the three before, skipping the pandemic, alongside average room prices by year.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#keeping-the-lights-on')" >Keeping the lights on
A site run by one person has to pay its own way, and Coworkations has tried a few. Paid listings and a traveler membership on Stripe in 2019, moved to Paddle a year later, gave way to reader discount codes in 2023, and in 2026 to featured slots that retreats can book, which show managers a preview of their own retreat in the slot before they buy.
tapped = false, 1500); navigator.clipboard?.writeText(location.href.split('#')[0] + '#under-the-hood')" >Under the hood
Django and Postgres with PostGIS and full-text search, Vue 3 and Tailwind 4
Pages cached in Redis for a day, ratings precomputed, and queries flattened and indexed so the biggest retreats stay quick
Share cards for every retreat, trip and search, rendered by my Cloudflare screenshot worker and warmed before anyone shares them
Sign-in with Google, Twitter, magic links and passkeys, with settings for every email and account deletion that can keep your reviews
Prices stored per room type in each retreat's currency, and converted with daily exchange rates only when shown
MapLibre maps, images resized on the fly, and gunicorn with gevent
CI against PostGIS and Redis with linting, deploys from a self-hosted GitHub Actions runner, and Sentry for errors
