Inspiration
Walk into any animal shelter and you'll find the same scene: dedicated staff stretched impossibly thin, juggling feeding schedules, medical care, adoptions, and — somewhere at the bottom of the to-do list — social media.
A shelter with 80 animals might post 3 or 4 a week, not because they don't care, but because writing a compelling caption, resizing a photo, logging into three different platforms, and repeating that process for every pet is genuinely exhausting work.
The math is stark. If a shelter has 100 animals and can only post 4 per week, it takes over 6 months to give every pet a single moment of visibility.
And that's assuming no new animals come in. In reality, the queue never clears.
I built PawPost because I believed that number should be close to zero — every pet, every platform, every day, with almost no manual effort.
What it does
PawPost is a multi-tenant social media automation platform built specifically for animal shelters.
Staff upload a pet photo and Claude AI instantly extracts the animal's species, breed, approximate age, gender, and personality traits directly from the image. It then generates a ready-to-post adoption caption (≤295 characters) in the shelter's chosen tone — warm and hopeful, playful and fun, professional, or urgent.
With one click, the post publishes simultaneously to Bluesky, Facebook, and Instagram.
Shelters can also:
- Schedule posts for specific times
- Manage a full posting queue with search and filters
- Review adoption inquiries from potential adopters
All from a single dashboard.
Each shelter is a fully isolated tenant with its own staff accounts, pet profiles, social credentials, and posting schedule.
How I built it
Frontend: React + TypeScript + Vite, deployed on Netlify
Backend: Node.js + Express + TypeScript, deployed on Railway
Database, Auth & Storage: Supabase (Postgres + Storage + Auth with Google OAuth)
AI: Anthropic Claude API for vision-based photo analysis and post generation
Social posting: Bluesky AT Protocol SDK, Facebook Graph API v25.0, Instagram Graph API
Automation: Self-hosted n8n on Railway for scheduled multi-tenant posting every 30 minutes
The posting pipeline flows through a single postPetToBluesky() helper. It:
- Authenticates with Bluesky
- Uploads the image blob
- Creates the post with rich-text hashtag facets
- Marks the pet as posted in the database
- Returns the API response immediately
After that, it triggers Facebook and Instagram posting in the background using a non-blocking Promise.all().
Challenges I ran into
Instagram's 2-step posting flow
Unlike Bluesky and Facebook, Instagram requires creating a media container first, then polling until it's ready before publishing. I implemented a status-polling loop (checking every 2 seconds, up to 60 seconds) to handle variable processing times.
Facebook token management
Short-lived User tokens from the Graph API Explorer kept expiring. I switched to a System User token via Meta Business Manager, which does not expire.
Non-blocking social posting
Early versions made users wait 10+ seconds for Instagram to finish before the UI responded. I fixed this by returning the response immediately after Bluesky posts, then firing Facebook and Instagram in the background.
Multi-tenant scheduling
Building an n8n workflow that dynamically serves all organizations at their own posting intervals required a custom /due-for-posting endpoint that calculates which organizations are ready based on their last post time.
Accomplishments that I am proud of
A shelter staff member can go from a raw photo to a live post on three platforms in under 30 seconds.
The AI photo analysis is genuinely impressive — it correctly identifies breeds, estimates ages, and picks up on personality from body language and posture.
I am especially proud that the hardest part of the UX — writing a good caption — is the part the user never has to do.
I am also proud of the architecture:
- Every shelter is a fully isolated tenant
- A single n8n workflow serves all tenants
- The entire posting pipeline (Bluesky, Facebook, Instagram) is handled by one backend function
What I learned
- Claude's vision capabilities go far beyond simple image description — with the right prompt, it can extract structured, form-ready data from a photo
- Instagram's Graph API has significantly more friction than Bluesky or Facebook — the container polling pattern is a non-obvious requirement
- Non-blocking architecture matters for UX — users don't need to wait for every downstream side effect to complete
- Meta's System User tokens (via business.facebook.com) are the right long-term solution for stable, non-expiring API access
What's next for PawPost
- Engagement analytics — track likes, reposts, and replies per pet across platforms to identify what drives the most interest
- Automatically import pet profiles from existing shelter databases so staff never have to enter data twice

Log in or sign up for Devpost to join the conversation.