Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Syncs your Foursquare/Swarm checkins to your ATProto PDS as com.barryfrost.checkin records. Runs on Val.Town's free tier as a 15-minute cron.
- Go to https://foursquare.com/developers/ and create a new app.
- Add
http://localhost:8765/callbackas an allowed Redirect URI. - Note your Client ID and Client Secret.
FSQ_CLIENT_ID=<id> FSQ_CLIENT_SECRET=<secret> deno task bootstrap
A browser window will open. Log in and approve. The token is printed to your terminal — it doesn't expire.
- Go to https://bsky.app/settings/app-passwords
- Create a new app password named
fsq2pds.
-
Install the
vtCLI: https://docs.val.town/cli/ -
From this directory run
vt push(or use the Val.Town editor to paste the files). -
Set these environment variables in Val.Town settings:
Variable Value FSQ_OAUTH_TOKENToken from step 2 FSQ_API_VERSION20240101BSKY_HANDLEYour Bluesky handle BSKY_APP_PASSWORDApp password from step 3 -
Open
cron.tsin Val.Town and add a cron trigger set to every 15 minutes.
- Trigger manually (first run). It will set the sync cursor to now and exit — no records written yet. Check the logs for
First run: launch cursor set to .... - Check in on Swarm.
- Trigger again (or wait up to 15 minutes). Check the logs for
Synced <id> (<venue>) → at://.... - View your records at:
https://pdsls.dev/at://<your-did>/com.barryfrost.checkin
{ "$type": "com.barryfrost.checkin", "createdAt": "2024-06-01T14:30:00.000Z", "location": { "$type": "community.lexicon.location.fsq", "fsq_place_id": "abc123def456", "name": "Blue Bottle Coffee", "latitude": "37.776", "longitude": "-122.418" }, "address": "123 High Street, London, UK", "category": "Coffee Shop", "comment": "Best flat white in town", "photos": [ { "image": { "$type": "blob", "ref": { "$link": "bafyrei..." }, "mimeType": "image/jpeg", "size": 245678 } } ] }
address, category, comment, and photos are all optional — omitted when the source checkin has no value for them. The lexicon doc itself is maintained in the barryfrost-v7 repo, not here.
- Only new checkins are synced. Nothing before the first run is imported. Use
deno task backfillto import historical checkins, anddeno task backfill-shoutsto addcommentto already-synced records whose shout predates that feature. - Photos: fetched at FSQ's
1024x1024size. Skipped if >1MB or unreachable. - Edits/deletes: not synced. Records are write-once. Delete PDS records manually if needed. (
backfill-shoutsis a one-time exception that patchescommentonto existing records.) - If a run fails mid-way, the cursor stays at the last successful checkin. The next run replays cleanly — duplicate protection is handled by the
seen_checkinstable.