# Platform Specs & Integration Guide: Instagram, TikTok, Nextdoor **Target platforms for your pipeline.** This document replaces the generic platform coverage in the original analysis with specific specs, API details, and implementation guidance for your three platforms. --- ## Table of Contents 1. [Platform Comparison Matrix](#1-platform-comparison-matrix) 2. [Instagram — Full Spec](#2-instagram--full-spec) 3. [TikTok — Full Spec](#3-tiktok--full-spec) 4. [Nextdoor — Full Spec](#4-nextdoor--full-spec) 5. [Updated Knowledge File: platform_guidelines.md](#5-updated-knowledge-file-platform_guidelinesmd) 6. [Updated Agent Modifications](#6-updated-agent-modifications) 7. [Updated Environment Variables](#7-updated-environment-variables) 8. [Publishing Flow Per Platform](#8-publishing-flow-per-platform) 9. [Key Differences from Original System](#9-key-differences-from-original-system) --- ## 1. Platform Comparison Matrix | Dimension | Instagram | TikTok | Nextdoor | |-----------|-----------|--------|----------| | **Primary format** | Feed (1:1), Reels (9:16), Stories (9:16) | Vertical video (9:16) | Feed image (1:1), Display (16:9) | | **Video max length** | Reels: 15 min (ads: keep ≤30s) | 10 min (ads: keep 15-30s) | 2-120s (keep ≤30s) | | **Image dimensions** | Feed: 1080x1080, Portrait: 1080x1350 | N/A (video-first) | 1200x1200 (spotlight), 1200x628 (display) | | **Video dimensions** | 1080x1920 (9:16) | 1080x1920 (9:16) | 1080x1920 (9:16) or 1920x1080 (16:9) | | **API type** | Instagram Graph API (REST) | Content Posting API (REST) | Ads API (GraphQL) | | **Auth** | OAuth via Meta Business Login | OAuth 2.0 + PKCE | OAuth2 / Bearer / Basic | | **Publishing flow** | Create container → wait → publish | Init upload → upload video → direct post | Create campaign → ad group → ad → creative | | **Token expiry** | 60 days (long-lived) | 24 hours (refreshable) | Varies | | **Organic posting** | Yes (via Graph API) | Yes (Content Posting API) | Limited (2 free/month for business) | | **Tone** | Aspirational, polished, punchy | Raw, authentic, trend-driven | Neighborly, local, trustworthy | | **Audience** | Broad consumer, visual-first | Gen Z / Millennials, entertainment-first | Homeowners, local community, 25-65 | --- ## 2. Instagram — Full Spec ### Ad Formats & Dimensions | Format | Dimensions | Aspect Ratio | Max File Size | Duration | |--------|-----------|--------------|---------------|----------| | **Feed Post** | 1080 x 1080 px | 1:1 (square) | 30 MB (image) | — | | **Feed Portrait** | 1080 x 1350 px | 4:5 | 30 MB | — | | **Feed Landscape** | 1080 x 566 px | 1.91:1 | 30 MB | — | | **Stories** | 1080 x 1920 px | 9:16 | 4 GB (video) | ≤15s per clip | | **Reels** | 1080 x 1920 px | 9:16 | 4 GB | ≤90s (API), rec ≤30s for ads | | **Carousel** | 1080 x 1080 px | 1:1 | 30 MB per card | Up to 10 cards | ### Safe Zones - **Stories/Reels top:** Leave 14% (250px) clear for username/camera icons - **Stories/Reels bottom:** Leave 20% (340px) clear for CTA/swipe-up UI - **Key content:** Center of frame ### Video Specs - **Format:** MP4 (H.264 codec preferred) - **Frame rate:** 24-30 fps (30 recommended) - **Audio:** AAC, 128kbps+ - **Captions:** Recommended (80% of users watch with sound off) ### Caption Guidelines - **Length:** ≤125 chars for ads (2 lines visible), up to 2200 chars for organic - **Structure:** Hook → Value/Vibe → CTA → line break → Hashtags (3-5) - **Emojis:** 1-2 max ### API Integration **Permissions needed:** - `instagram_business_basic` - `instagram_business_content_publish` **Publishing flow (Node.js):** ```javascript // Step 1: Create media container const container = await fetch( `https://graph.facebook.com/v20.0/${IG_USER_ID}/media`, { method: 'POST', body: JSON.stringify({ image_url: supabasePublicUrl, // Must be publicly accessible caption: captionText, access_token: INSTAGRAM_ACCESS_TOKEN // For Reels: add media_type: 'REELS', video_url: videoPublicUrl }) } ); const { id: containerId } = await container.json(); // Step 2: Check container status (for video) // Poll GET /{containerId}?fields=status_code until status_code === 'FINISHED' // Step 3: Publish const publish = await fetch( `https://graph.facebook.com/v20.0/${IG_USER_ID}/media_publish`, { method: 'POST', body: JSON.stringify({ creation_id: containerId, access_token: INSTAGRAM_ACCESS_TOKEN }) } ); ``` **Rate limit:** 200 requests/hour/account **Token management:** - Long-lived tokens expire after **60 days** - Exchange short-lived → long-lived via `/oauth/access_token` - Set calendar reminder or automated refresh before expiry ### Sources - [Instagram Graph API Complete Guide 2026](https://elfsight.com/blog/instagram-graph-api-complete-developer-guide-for-2026/) - [Instagram Content Publishing Docs](https://developers.facebook.com/docs/instagram-platform/content-publishing/) - [Instagram Reels API Guide](https://www.getphyllo.com/post/a-complete-guide-to-the-instagram-reels-api) - [Instagram Ad Dimensions 2026](https://admanage.ai/blog/instagram-ad-dimensions) --- ## 3. TikTok — Full Spec ### Ad Formats & Dimensions | Format | Dimensions | Aspect Ratio | Max File Size | Duration | |--------|-----------|--------------|---------------|----------| | **In-Feed Video** | 1080 x 1920 px | 9:16 (required) | 500 MB | 9-60s (ads), up to 10 min (organic) | | **Square** | 1080 x 1080 px | 1:1 | 500 MB | Same | | **Landscape** | 1920 x 1080 px | 16:9 | 500 MB | Same | **9:16 vertical is mandatory for best performance** — square and landscape are technically supported but consistently underperform. ### Video Specs - **Format:** MP4, MOV, MPEG, 3GP, AVI - **Min resolution:** 540 x 960 (9:16) / 640 x 640 (1:1) - **Bitrate:** ≥516 kbps - **Frame rate:** 24-30 fps - **Audio:** Required (TikTok is sound-on by default) ### Creative Best Practices - **Hook in first 3 seconds** (not 5 — TikTok scrolls fast) - **On-screen text:** Large, central, ≤6 words per frame - **Keep key elements centered** — description/logo overlay crops edges - **Optimal length:** 15-30s for ads, 21-34s per TikTok's own data - **Style:** Raw/authentic outperforms polished — "made on TikTok, not for TikTok" - **Sound:** Essential — 93% of top-performing TikToks use audio - **Subtitles:** Always include (accessibility + sound-off viewing) ### Caption Guidelines - **Length:** Up to 4000 chars (but shorter = better for engagement) - **Hashtags:** 3-5 relevant hashtags, mix trending + niche - **Tone:** Casual, conversational, trend-aware, slightly irreverent - **No hard-sell CTAs** — soft CTAs work better ("link in bio", "check this out") ### API Integration **TikTok Content Posting API — OAuth 2.0 + PKCE flow:** ```javascript // Step 1: Redirect user to TikTok authorization const authUrl = `https://www.tiktok.com/v2/auth/authorize/?` + `client_key=${CLIENT_KEY}&scope=user.info.basic,video.publish` + `&response_type=code&redirect_uri=${REDIRECT_URI}&state=${csrfState}`; // Step 2: Exchange code for access token const tokenRes = await fetch('https://open.tiktokapis.com/v2/oauth/token/', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_key: CLIENT_KEY, client_secret: CLIENT_SECRET, code: authCode, grant_type: 'authorization_code', redirect_uri: REDIRECT_URI }) }); const { access_token, refresh_token } = await tokenRes.json(); // Step 3: Init video upload const initRes = await fetch('https://open.tiktokapis.com/v2/post/publish/video/init/', { method: 'POST', headers: { 'Authorization': `Bearer ${access_token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ post_info: { title: 'Your caption here #hashtag', privacy_level: 'PUBLIC_TO_EVERYONE', disable_duet: false, disable_comment: false, disable_stitch: false }, source_info: { source: 'FILE_UPLOAD', video_size: fileSize, chunk_size: fileSize, total_chunk_count: 1 } }) }); const { data: { publish_id, upload_url } } = await initRes.json(); // Step 4: Upload video binary to upload_url await fetch(upload_url, { method: 'PUT', headers: { 'Content-Range': `bytes 0-${fileSize - 1}/${fileSize}`, 'Content-Type': 'video/mp4' }, body: videoBuffer }); ``` **Token management:** - Access tokens expire in **24 hours** - Refresh tokens last **365 days** - **Must implement auto-refresh** — unlike Instagram's 60-day window, TikTok tokens expire daily **Two posting modes:** 1. **Direct Post** — content goes live immediately (use for automation) 2. **Upload to Inbox** — queues in creator's drafts for manual review **No native scheduling** — implement your own via cron/BullMQ/Redis ### Sources - [TikTok Content Posting API Docs](https://developers.tiktok.com/products/content-posting-api/) - [TikTok Direct Post Reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post) - [TikTok OAuth Token Management](https://developers.tiktok.com/doc/oauth-user-access-token-management) - [TikTok Ad Specs 2026](https://admanage.ai/blog/tiktok-ad-specs) - [TikTok Content Posting Developer Guide 2026](https://www.tokportal.com/learn/tiktok-content-posting-api-developer-guide) --- ## 4. Nextdoor — Full Spec ### Important: Nextdoor is Different Nextdoor operates fundamentally differently from Instagram/TikTok: - **Audience:** Hyperlocal — homeowners, families, local businesses in verified neighborhoods - **Tone:** Neighborly, trustworthy, community-first (NOT flashy marketing speak) - **API access:** Ads API requires partnership application; organic posting limited to 2 free business posts/month - **Ad format:** Primarily static image ads; video supported but not the primary format - **Targeting:** Geographic (neighborhood-level), demographic, interest-based — leverages 14 years of verified neighbor data ### Ad Formats & Dimensions | Format | Dimensions | Aspect Ratio | Max File Size | Notes | |--------|-----------|--------------|---------------|-------| | **Spotlight Ad** | 1200 x 1200 px | 1:1 | 1 MB | JPG/PNG, premium placement | | **Display Ad** | 1200 x 628 px | ~1.91:1 | 150 MB | JPG/PNG/GIF | | **Multi-destination (Carousel)** | 1200 x 1200 px min | 1:1 | 150 MB | 2-10 images, JPG/PNG | | **Video Ad** | Variable | 16:9 or 1:1 | 500 MB | MP4/MOV, 2-120s, rec ≤30s | | **Video Thumbnail** | 1200 x 628 px | ~16:9 | — | Auto-generated or custom | | **Lead Gen (Image)** | 1200 x 628 px | 1.91:1 | 150 MB | JPG/PNG | | **Lead Gen (Video)** | Variable | 16:9 or 1:1 | 500 MB | MP4/MOV | ### Creative Best Practices - **Subtitles on video** — always (many users browse silently) - **Keep video ≤30 seconds** for best engagement - **Local feel** — avoid stock-photo-corporate look; authentic, neighborhood imagery performs best - **CTA clarity** — "Learn More", "Get a Quote", "Visit Us" (direct, local-action oriented) - **No aggressive sales language** — Nextdoor's community first-ethos; "hard sell" gets reported ### Tone Guidelines (Critical for Nextdoor) - **DO:** Sound like a helpful neighbor, reference local context, use warm/genuine language - **DON'T:** Sound like a national brand blast, use hype/urgency tactics, be salesy - **Think:** "Hey neighbors, we just launched..." NOT "LIMITED TIME OFFER! ACT NOW!" ### API Integration **Nextdoor Ads API — GraphQL-based:** The Ads API is a single GraphQL endpoint supporting queries and mutations across 7 resources: profile, advertiser, campaign, ad group, ad, creative, media, reports. **Access:** Requires application through [developer.nextdoor.com](https://developer.nextdoor.com/). Not self-service — you need partnership approval. **Auth options:** Basic Auth, Bearer Token, or OAuth2 **Campaign creation flow:** ``` 1. Create Advertiser account (or use existing) 2. Create Campaign (objective, budget, schedule) 3. Create Ad Group (targeting, bid strategy) 4. Upload Media (image/video creative) 5. Create Ad (links creative to ad group) 6. Campaign goes into review → approved → live ``` **What must be done in Nextdoor Ads Manager (not API):** - Initial signup - Payment method setup - Custom audience creation - Media archiving **Organic posting alternative:** - Nextdoor Publish API allows programmatic organic posts - **Limit:** 2 free business posts/month - Partners like Orlo and ZenCity can schedule and geo-target posts - Best for: local news, community updates, soft-sell brand presence ### Env Variables Needed ```bash # Nextdoor Ads API NEXTDOOR_API_TOKEN=YOUR_BEARER_TOKEN # Or use OAuth2 credentials NEXTDOOR_ADVERTISER_ID=YOUR_ADVERTISER_ID # From Ads Manager # Nextdoor Publish API (organic) NEXTDOOR_PUBLISH_API_KEY=YOUR_KEY # If using organic posting ``` ### Sources - [Nextdoor Ads API Overview](https://developer.nextdoor.com/docs/advertising-overview) - [Nextdoor Developer Portal](https://developer.nextdoor.com/) - [Nextdoor Creative Specs](https://business.nextdoor.com/en-us/nam/nextdoor-ads-manager/creative-specs) - [Nextdoor Ad Specs 2025 (PDF)](https://coegipartners.com/wp-content/uploads/2025/01/NextDoor-Specs-2025.pdf) - [Nextdoor Ads API Launch Announcement](https://about.nextdoor.com/press-releases/nextdoor-launches-ads-api-program-offering-advertisers-an-easier-way-to-extend-their-campaigns-to-nextdoor) --- ## 5. Updated Knowledge File: platform_guidelines.md Replace the original 3-platform file with this structure: ```markdown # Platform Guidelines: [Your Brand] **Purpose:** Ensures all content is correctly formatted and styled per platform before publishing. Reference before finalizing any post, video, or caption. --- ## 1. Platform Overview | Platform | Content Types | Primary Tone | Hashtags | |----------|--------------|--------------|----------| | **Instagram** | Feed (1:1), Reels (9:16), Stories (9:16), Carousel | Aspirational, polished, punchy | Required (3-5) | | **TikTok** | Vertical video (9:16) only | Raw, authentic, trend-driven | Required (3-5) | | **Nextdoor** | Feed image (1:1), Display (16:9), Video | Neighborly, local, trustworthy | Not used | --- ## 2. Instagram ### Image Specs | Format | Dimensions | Ratio | |--------|-----------|-------| | Feed Post | 1080 x 1080 px | 1:1 | | Feed Portrait | 1080 x 1350 px | 4:5 | | Story/Reel | 1080 x 1920 px | 9:16 | ### Caption Rules - Length: 1-3 sentences before hashtags - Structure: Hook + Value + CTA + line break + Hashtags - Emojis: 1-2 from approved set - CTA: Always include, place before hashtags ### Safe Zones (Stories/Reels) - Top 14% (250px) — keep clear - Bottom 20% (340px) — keep clear --- ## 3. TikTok ### Video Specs | Property | Requirement | |----------|------------| | Dimensions | 1080 x 1920 px (9:16 mandatory) | | Length | 15-30s optimal for ads | | Format | MP4, ≥516 kbps | | Audio | Required (sound-on platform) | | Subtitles | Always include | ### Caption Rules - Tone: Casual, conversational, trend-aware - Hashtags: 3-5 (mix trending + niche) - No hard-sell CTAs — use "link in bio", "check this out" - Hook in first 3 seconds - On-screen text: ≤6 words per frame, large, centered ### Key Difference from Instagram TikTok rewards authenticity over polish. Content should feel "made on TikTok" — raw, energetic, personality-driven. Overproduced content underperforms. --- ## 4. Nextdoor ### Image Specs | Format | Dimensions | Ratio | |--------|-----------|-------| | Spotlight Ad | 1200 x 1200 px | 1:1 | | Display Ad | 1200 x 628 px | ~1.91:1 | | Video | MP4/MOV | 16:9 or 1:1 | ### Tone Rules (CRITICAL) - Sound like a helpful neighbor, NOT a national brand - Reference local context when possible - Warm, genuine, community-first language - NO hype, urgency tactics, or aggressive sales language - CTA style: "Learn More", "Get a Quote", "Visit Us" ### Caption Rules - Keep it conversational and local - No hashtags (Nextdoor doesn't use them) - Focus on community value, not product pushing - Video: ≤30 seconds with subtitles ### Posting Limits - Organic: 2 free business posts/month - Ads: Via Ads Manager or Ads API (requires partnership) ``` --- ## 6. Updated Agent Modifications ### Ad Creative Designer — Changes The original system only generated 1080x1080 Instagram square ads. For your three platforms, the agent needs to produce **multiple format variants per campaign:** | Platform | Static Ad Size | Video Size | |----------|---------------|------------| | Instagram Feed | 1080 x 1080 px | 1080 x 1920 px (Reels) | | Instagram Stories | 1080 x 1920 px | 1080 x 1920 px | | TikTok | N/A (video only) | 1080 x 1920 px | | Nextdoor Spotlight | 1200 x 1200 px | — | | Nextdoor Display | 1200 x 628 px | 1920 x 1080 or 1080 x 1080 | **Playwright screenshot configs needed:** ```javascript const PLATFORM_CONFIGS = { instagram_feed: { width: 1080, height: 1080 }, instagram_stories: { width: 1080, height: 1920 }, nextdoor_spotlight: { width: 1200, height: 1200 }, nextdoor_display: { width: 1200, height: 628 }, }; ``` ### Video Ad Specialist — Changes Must now produce **two video variants:** | Platform | Dimensions | Aspect | Length | Style | |----------|-----------|--------|--------|-------| | Instagram Reels | 1080 x 1920 | 9:16 | ≤30s | Polished, branded | | TikTok | 1080 x 1920 | 9:16 | 15-30s | Raw, authentic, trend-driven | | Nextdoor (optional) | 1080 x 1080 or 1920 x 1080 | 1:1 or 16:9 | ≤30s | Local, warm, community feel | **Key insight:** Instagram and TikTok share the same 9:16 dimensions but the **creative style should differ significantly.** The Remotion composition should accept a `style` parameter: - `style: "polished"` → clean motion graphics, brand colors, professional typography (Instagram) - `style: "authentic"` → rougher transitions, text overlays, trend-aware pacing (TikTok) - `style: "local"` → warm, simple, community-focused (Nextdoor) ### Copywriter Agent — Changes Must now produce **3 platform-specific copy files** instead of the original 3: ``` outputs/{task_name}_{date}/copy/ ├── instagram_caption.txt # Hook + Value + CTA + hashtags ├── tiktok_caption.txt # Casual, trend-aware, soft CTA + hashtags ├── nextdoor_post.txt # Neighborly, local, no hashtags └── copy_output.json # Consolidated structured data ``` ### Distribution Agent — Changes Now handles **3 different API integrations:** | Platform | API | Auth | Publishing Flow | |----------|-----|------|----------------| | Instagram | Graph API (REST) | OAuth, 60-day tokens | Create container → wait FINISHED → publish | | TikTok | Content Posting API (REST) | OAuth 2.0 + PKCE, 24-hour tokens | Init upload → PUT video binary → direct post | | Nextdoor | Ads API (GraphQL) | Bearer/OAuth2, requires partnership | Campaign → Ad Group → Creative → Ad | **Token refresh automation is critical:** - Instagram: refresh before 60-day expiry - TikTok: **auto-refresh daily** (24-hour expiry) - Nextdoor: depends on auth method --- ## 7. Updated Environment Variables ```bash # .env.example # === Research === TAVILY_API_KEY=tvly-YOUR_API_KEY # === Media Storage === SUPABASE_URL=YOUR_SUPABASE_PROJECT_URL SUPABASE_SERVICE_ROLE_KEY=YOUR_SUPABASE_SERVICE_ROLE_KEY # === Instagram Graph API === INSTAGRAM_ACCOUNT_ID=YOUR_INSTAGRAM_PROFESSIONAL_ACCOUNT_ID INSTAGRAM_ACCESS_TOKEN=YOUR_INSTAGRAM_USER_ACCESS_TOKEN # Permissions: instagram_business_basic, instagram_business_content_publish # Token expires: 60 days — implement refresh # === TikTok Content Posting API === TIKTOK_CLIENT_KEY=YOUR_TIKTOK_APP_CLIENT_KEY TIKTOK_CLIENT_SECRET=YOUR_TIKTOK_APP_CLIENT_SECRET TIKTOK_ACCESS_TOKEN=YOUR_TIKTOK_USER_ACCESS_TOKEN TIKTOK_REFRESH_TOKEN=YOUR_TIKTOK_REFRESH_TOKEN # Token expires: 24 hours — MUST auto-refresh daily # Refresh token expires: 365 days # === Nextdoor Ads API === NEXTDOOR_API_TOKEN=YOUR_NEXTDOOR_BEARER_TOKEN NEXTDOOR_ADVERTISER_ID=YOUR_NEXTDOOR_ADVERTISER_ID # Requires partnership application at developer.nextdoor.com ``` --- ## 8. Publishing Flow Per Platform ### Instagram ``` Media generated locally → Upload to Supabase (public URL required) → POST /{ig-user-id}/media (create container with public URL) → Poll container status until FINISHED → POST /{ig-user-id}/media_publish (publish) → Return post ID ``` ### TikTok ``` Video generated locally → POST /v2/post/publish/video/init/ (get upload_url) → PUT video binary to upload_url → TikTok processes and publishes → Return publish_id ``` Note: TikTok accepts direct file upload — **no Supabase intermediary needed** for TikTok (unlike Instagram). However, keeping Supabase as the central store is still good practice for archival. ### Nextdoor ``` For Ads (via Ads API): → Upload media asset via API → Create Campaign (objective, budget) → Create Ad Group (targeting, schedule) → Create Ad (link creative + copy) → Submit for review → auto-approved → live For Organic (via Publish API): → POST content via Publish API → Limited to 2 free posts/month ``` --- ## 9. Key Differences from Original System | Aspect | Original (Andy's System) | Your System | |--------|-------------------------|-------------| | **Platforms** | Instagram, YouTube, Threads | Instagram, TikTok, Nextdoor | | **Video style** | Single polished style | Multiple styles (polished, authentic, local) | | **Static ad sizes** | 1080x1080 only | 1080x1080, 1080x1920, 1200x1200, 1200x628 | | **API complexity** | 3 simple REST APIs | REST + REST + GraphQL (Nextdoor) | | **Token management** | Instagram 60-day only | Instagram 60-day + TikTok daily refresh | | **Tone variation** | Single brand voice | 3 platform-adapted voices from same brand identity | | **Nextdoor** | Not included | Requires partnership application + community-first creative | | **Supabase role** | Required for Instagram | Required for Instagram, optional for TikTok, required for Nextdoor ads | | **YouTube** | Included | Dropped (can add back) | | **Threads** | Included | Dropped (can add back) | | **Scheduling** | Basic advisory | Need custom scheduler for TikTok (no native scheduling API) | --- *Compiled March 2026. Verify API versions and access requirements before implementation.*