Create Anylist recipes from Instagram recipe posts.
iOS Shortcut
↓
POST /ingest { "url": "https://instagram.com/p/..." }
↓
┌─────────────────────────────────────────┐
│ Recipe Ingest Service (Docker) │
│ │
│ 1. Validate bearer token │
│ 2. Fetch post via Apify │
│ 3. Parse recipe with Claude Haiku │
│ 4. Create recipe in AnyList │
│ 5. Send push notification via ntfy.sh │
└─────────────────────────────────────────┘
# Install dependencies
pnpm install
# Copy and configure environment
cp .env.example .env
# Edit .env with your credentials
# Run locally
pnpm dev
# Test
curl -X POST http://localhost:3000/ingest \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.instagram.com/p/ABC123/"}'Accepts an Instagram URL and processes it into a recipe.
Request:
POST /ingest HTTP/1.1
Authorization: Bearer <API_TOKEN>
Content-Type: application/json
{
"url": "https://www.instagram.com/p/ABC123/"
}Response:
HTTP/1.1 202 Accepted
{
"status": "processing",
"message": "Recipe ingestion started"
}Health check (no auth required).
HTTP/1.1 200 OK
{"status": "ok"}| Variable | Description |
|---|---|
API_TOKEN |
Bearer token for authenticating requests |
APIFY_TOKEN |
Apify API token for Instagram scraping |
ANYLIST_EMAIL |
AnyList account email |
ANYLIST_PASSWORD |
AnyList account password |
ANTHROPIC_API_KEY |
Claude API key for recipe parsing |
NTFY_TOPIC |
ntfy.sh topic for notifications |
PORT |
Server port (default: 3000) |
Create a scoped token at Apify Console → Settings → Integrations:
- Actor:
nH2AHrwxeTRJoN5hX(apify/instagram-post-scraper)- Run permission
No dataset permissions required (uses sync API).
├── src/
│ ├── index.ts # Express server + routes
│ ├── apify.ts # Instagram fetching (Apify sync API)
│ ├── parser.ts # Claude Haiku recipe parsing
│ ├── anylist.ts # AnyList recipe creation
│ └── notify.ts # ntfy.sh notifications
├── scripts/
│ └── postinstall.js # Patches anylist-napi ESM bug
├── Dockerfile
├── package.json
└── tsconfig.json
docker build -t feed-me-recipe .
docker run -d \
--name feed-me-recipe \
--env-file .env \
-p 3000:3000 \
feed-me-recipeExpose the service securely without opening ports:
- Create tunnel in Cloudflare Zero Trust dashboard
- Add public hostname pointing to
http://localhost:3000 - Optionally configure Zero Trust access policies (or rely on bearer token auth)
Claude Haiku extracts structured recipe data from Instagram captions:
{
"is_recipe": true,
"confidence": 0.95,
"recipe": {
"name": "Sheet Pan Beef Kefta Wraps",
"servings": "4 servings",
"prepTime": 20,
"cookTime": 15,
"ingredients": [
{"name": "ground beef", "quantity": "1.5 lbs"},
{"name": "garlic", "quantity": "8 cloves", "note": "minced"}
],
"steps": [
"Preheat oven to 400°F...",
"Mix beef with spices..."
]
}
}Posts without recipes return {"is_recipe": false, "reason": "..."}.
anylist-napiprepTime/cookTime values save as 0 (upstream bug)
- Confidence threshold → flag low-confidence for manual review
- Job queue for reliability
- Recipe deduplication
- Web UI for review/edit
- Multi-user support