Automatically detects new Google Form submissions (via a linked Google Sheet), generates a blog post with AI, and pushes it to Substack as a draft.
Rendering mermaid diagram...
- Poll Google Sheet — An interval val runs on a schedule (e.g. every 15 min). It fetches all rows from the unlisted Google Sheet via the public CSV/JSON export URL (no API key needed for unlisted sheets).
- Deduplicate — Each row's timestamp (or row number) is tracked in SQLite so we never process the same submission twice.
- Generate Blog Post — New submissions are sent to OpenAI (via Val Town's
std/openai) to generate a full blog post (title + HTML body). - Push to Substack — The generated post is created as a draft on Substack via its internal API (
POST /api/v1/drafts), authenticated with yoursubstack.sidcookie. - Log & Review — You review and publish drafts in Substack's UI.
In the val's settings (left sidebar → Environment Variables), add these three:
The ID from your Google Sheet URL. For example, if the URL is:
https://docs.google.com/spreadsheets/d/1aBcDeFgHiJkLmNoPqRsTuVwXyZ/edit
then the ID is 1aBcDeFgHiJkLmNoPqRsTuVwXyZ.
⚠️ The sheet must be set to "Anyone with the link can view" (unlisted) for the pipeline to read it without Google API credentials.
Your substack.sid cookie, which authenticates API requests as you.
- Log into substack.com in Chrome
- Open DevTools: F12 (or right-click → Inspect)
- Go to the Application tab → Cookies →
https://substack.com - Find the cookie named
substack.sidand copy its Value
⚠️ Treat this like a password — it gives full access to your Substack account. It stays valid for months as long as you don't log out.
Your Substack publication hostname, e.g. yourname.substack.com (no https://, just the hostname).
Run test-google-sheet.ts. You should see your column names and a preview of the first few rows. If it fails, double-check:
- The sheet ID is correct
- The sheet sharing is set to "Anyone with the link"
Run test-substack.ts. This will:
- Verify your cookie authenticates successfully (prints your name/email)
- Create a test draft post on your Substack
If it succeeds, check your Substack dashboard drafts — you should see a test draft. You can safely delete it.
Once both test scripts pass, the connections are working and we can build the main cron pipeline.
README.md— This filetest-google-sheet.ts— Script to test Google Sheet connectivitytest-substack.ts— Script to test Substack API connectivitymain.ts— (TODO) The main interval cron that ties it all together
- Project plan
- Test Google Sheet connection
- Test Substack connection
- AI blog post generation
- Main pipeline cron
- Dashboard (optional)