What this document is
Jaime builds custom Astro sites for Aspire clients. Clients inevitably ask to show their Instagram or Facebook feed on the site. The stock Meta embed is a widget with Meta's branding, Meta's layout, and no CSS control. That's a non-starter for a brand-quality build.
The goal: a JSON API layer (bought or built) that Astro can fetch() at build time or runtime, returning an array of post objects. Jaime maps each object to an Astro component with full brand control. The feed looks like the client's site, not Instagram's widget.
This version of the doc was rewritten 2026-06-09 after Topher pushed on the previous draft: "why use a third party at all, and how do these companies get around Instagram's bot detection?" The honest answer reframes the whole build-vs-buy decision β see Front Door vs Back Door next, then the verdict.
The reframe β front door vs back door
The previous draft of this doc framed Behold, Curator, EmbedSocial as "services that solved Meta's bot detection so you don't have to." That's wrong, and it warps the build-vs-buy decision. The reputable third parties don't solve bot detection β they never face it.
Front door Β· official Meta Graph API
Behold, Curator, EmbedSocial β and any homegrown integration we'd build β go through Meta's official front door:
- A registered Meta Developer App.
- Each client clicks "Allow" via OAuth. Meta hands the app a token scoped to that account.
- App calls
graph.instagram.com/graph.facebook.comwith that token. - Nothing to detect. No bot, no fingerprinting, no IP rotation. The traffic is sanctioned.
This is the only path that lasts.
Back door Β· scrape the public web
Playwright, instagrapi, the private mobile API β anything that pretends to be a human browser hitting instagram.com:
- No OAuth, no token, no Meta app.
- Meta's anti-bot stack (TLS fingerprinting, JS challenges, IP reputation) fires every time.
- Login walls progressively gate content. Account bans + IP blocks are real.
- UI changes break the scraper 3β5Γ/yr.
Reputable services don't use this path. We shouldn't either.
So what does $30/mo Behold actually buy?
Not a technical moat. A bureaucratic + maintenance burden transfer on three things only the vendor has economies of scale for:
- Meta App Review. Serving accounts you don't own = "Tech Provider" classification = formal app review with screencast-per-permission, business verification, and 2β4 weeks per submission round. First-submission rejection is the norm. End-to-end: 6β10 weeks realistic.
- Per-client OAuth + 60-day token refresh machinery. 10 clients = 10 OAuth flows + 10 refresh cron jobs + re-auth handling whenever a client rotates a password or revokes app access.
- The deprecation treadmill. Meta killed the Instagram Basic Display API Dec 4 2024 and broke everyone built on it. They renamed all the Instagram-Login scopes (
business_basicβinstagram_business_basic) on Jan 27 2025. They ship ~4 Graph API versions/year with a 2-year sunset clock. This is the genuinely nasty, unpredictable, on-call cost.
Item #3 is the load-bearing reason to buy a vendor at <5 clients. Items #1 and #2 are one-time setup vs ongoing rent.
A point of intellectual honesty: the previous draft bundled "DIY Meta Graph API" and "self-hosted scraper" together as twin "don't build" options. They are not the same thing. The scraper is a trap. A homegrown integration on the official API is a legitimate option Aspire chose to defer β for good reasons (App Review tax, low client count today) β but it's not architecturally bad. In fact it's philosophically aligned with Aspire's own pitch to clients: "stop renting from five vendors, bring it in-house." When the math flips, we should flip with it. See Section D β graduation trigger.
The verdict
Buy Behold.so Pro ($30/mo) now. Add Curator.io Business ($54/mo) only when a client actually requests Facebook posts. Build the homegrown-on-official-API version on M3 when the graduation trigger fires.
Why buy now
At 1β15 clients, $30/mo < 6β10 weeks of Topher's time for App Review + ongoing deprecation patching. Behold has a proper headless JSON API. The build option exists; it's just not the highest-leverage move this quarter.
Graduation trigger
Build the homegrown M3 version when (a) Aspire crosses ~25 active client feeds, where vendor cost approaches build cost, or (b) "we own the social pipeline" becomes a strategic selling point (e.g. bundled with Aspire Concierge), or (c) Behold ships a breaking change we can't tolerate. Earliest of the three.
What never makes sense
A scraper. Bot detection is real on the back door, the ToS gray area is real, breakage is real, and we'd be solving a problem the vendors don't even have. The scraper is not on the spectrum of "build options." See Section C.
Full survey of buy options at Section A. The real homegrown architecture (official API, on M3) is at Section B β including a build plan against confirmed 2026 Meta platform facts. Pricing model for what Aspire charges clients is at Section E.
A Β· Third-Party Service Survey
Evaluation criteria: (1) Does the service expose a headless JSON API that lets Jaime render posts with her own Astro/HTML/CSS? (2) What are the actual pricing tiers? (3) Does it handle both Instagram and Facebook from one subscription? All services in this section use Meta's official Graph API under the hood β front door. They just amortize the App Review + token management across all their customers.
Headless JSON API: Yes β the core differentiator. Every feed gets a unique public URL (https://feeds.behold.so/FEED_ID) returning a JSON array of post objects. No API key needed client-side; Behold handles token management server-side. CORS-enabled for whitelisted domains. Safe to fetch() from Astro's frontmatter (build-time) or a client component (runtime).
Per-post data fields: id, timestamp, permalink, mediaType, mediaUrl, sizes (small/medium/large/full WebP), caption, hashtags, likeCount, commentsCount, colorPalette, children (carousel). Account-level: username, bio, follower count.
Instagram + Facebook: Instagram only. No Facebook Page posts.
Under the hood: Uses the official Instagram API with Instagram Login (the replacement for Basic Display, shipped post-Dec 2024). Behold holds the Meta App Review approval; each client just clicks "Allow" via OAuth.
| Plan | Price | Sources / Feeds | Views/mo | JSON API |
|---|---|---|---|---|
| Free | $0 | 1 / 1 | 1,200 | Yes (Behold branding) |
| Starter | $10/mo | 3 / 3 | 15,000 | Yes, no branding |
| Pro β | $30/mo | 15 / 15 | 125,000 | Yes + Klaviyo |
| Scale | $60/mo | 30 / 30 | 500,000 | Yes + Klaviyo |
| Platform | $60 + usage/mo | Unlimited | 100K incl. | Yes + Admin API |
| Enterprise | $180/mo | Unlimited | Unlimited | Yes |
Platform plan note: Adds an Admin API for programmatic multi-client management ($0.45/feed/mo beyond 50 included). Designed for developers managing feeds at scale β the right tier once Aspire has 5+ active clients.
A "view" in Behold's model: each request to the feed URL counts as one view. A page load that fetches the feed = 1 view. At 125K views/mo on Pro, a 10-client portfolio with moderate traffic is comfortable.
Headless JSON API: Yes β but only on the Business plan ($54/mo). RESTful HTTP endpoint returning normalized JSON across all connected sources. Suitable for Astro fetch().
Instagram + Facebook: Yes β both in a single feed/subscription. Curator's main edge over Behold.
Pricing: Free (3 sources, 2K views, no API) Β· Pro $23/mo (5 sources, no API) Β· Business $54/mo (15 sources, API access) Β· Enterprise (custom).
Under the hood: Official Meta Graph API for both surfaces (Instagram Graph API for IG Business + Page Public Content Access for FB). Curator holds the Tech Provider approval. Clients still need Business/Creator IG accounts + a Facebook Page β no service can bypass that.
Add Curator when Facebook posts are a first-class requirement. At $54/mo it's less efficient as an agency-wide shared account unless multiple clients need multi-platform feeds.
Headless JSON API: Enterprise plan only, starting at $199/mo. Below that, widget-only.
Instagram + Facebook: Yes, 16+ sources supported.
Pricing: Free Β· Lite $15/mo Β· Starter $25/mo Β· Pro $99/mo Β· Enterprise $199/mo+.
The API wall at $199/mo kills this option for a small agency. Widget tiers can't meet the Jaime-owns-the-render requirement.
Headless JSON API: Yes β a read-only API returning unified JSON across all connected platforms. Available on Premium ($99/mo) and above.
Instagram + Facebook: Yes β plus TikTok, LinkedIn, YouTube, X. Single schema across all platforms.
Pricing: Pro Plus $49/mo (6 sources, 5K media/source, no API) Β· Premium $99/mo (15 sources, API included) Β· Enterprise (custom).
Becomes interesting if a client wants Facebook + Instagram + Google Reviews in one API call. Overkill for Instagram-only use.
Headless JSON API: No documented public headless API for custom rendering. Widget platform; customization stays inside the widget builder. Not suitable for Jaime's "full Astro control" requirement.
Pricing: Free (200 views, 1 widget) Β· Basic $6/mo Β· Pro $12/mo Β· Premium $24/mo. Widget-locked.
Ruled out for Aspire's brand-build use case.
Smash Balloon: WordPress plugin only ($49β$299/yr). No standalone API. Ruled out β Aspire builds Astro.
LightWidget: Widget-only, $10 one-time commercial license. Pure embed, no API.
SnapWidget: Widget-focused. No documented headless API.
Tagembed: Freeβ$40/mo Business. Aggregates 20+ platforms. No headless API documentation found.
| Service | Headless JSON API? | Min. API price | FB + IG? | Notes |
|---|---|---|---|---|
| Behold.so | Yes | $10/mo (Starter) | IG only | Best fit for IG-first + Astro |
| Curator.io | Yes | $54/mo (Business) | Yes | Best multi-platform option |
| EmbedSocial | Yes | $99/mo (Premium) | Yes | Full UGC platform; overkill |
| Juicer.io | Yes | $199/mo (Enterprise) | Yes | API wall too high |
| Elfsight | No | β | Yes | Widget-locked |
| Smash Balloon | No | β | Yes | WordPress only |
| LightWidget | No | β | IG only | Widget-only, $10 one-time |
| SnapWidget | No | β | IG only | Widget-only |
| Tagembed | No | β | Yes | Widget-first |
Aβ² Β· Why not GHL? (the tool we already run)
The obvious question: Aspire already runs many clients' CRMs on GoHighLevel (white-labeled as "Pulse"), and GHL's Social Planner already holds those clients' Instagram/Facebook connections. If GHL is already the token-holder, can we just read the feed from GHL and skip both the vendor and our own Meta App Review? Evaluated 2026-06-09. Answer: no β not for displaying a feed.
The disqualifier: publish-out, not read-in
GHL's Social Planner is a publishing tool. Its API operates on a GHL-managed post entity β posts you scheduled or published through GHL β not a mirror of the account's native Instagram feed. There is no "get account media" / "get feed" endpoint in the catalog. GET /social-media-posting/{locationId}/posts/{id} requires a GHL-internal post ID, so you can only ever retrieve posts GHL itself minted. Posts a client made directly in the Instagram app are invisible to GHL.
What GHL's API + MCP actually expose
The official GHL MCP server's 6 social tools (get-posts, get-post, create-post, edit-post, get-account, get-social-media-statistics) all map to that same GHL-post entity. get-account returns connected-account metadata only β no media. None return the native feed.
The root cause: GHL never asked Meta for read
A tool can only expose downstream what it was granted upstream. GHL's Instagram connection requests publishing scope (instagram_business_content_publish), not read-media (instagram_business_basic). GHL asked Meta for "let me post," not "let me read" β so a feed was never on the table, regardless of how rich the API looks. (High-confidence inference from Circa's GHL knowledge base + scope behavior, not yet string-confirmed β see test below.)
The 5-minute test that settles it to 100%
Against any live client location already connected to Social Planner, call POST /social-media-posting/{locationId}/posts/list and check whether the response contains any post that was made directly in the Instagram app and never touched by GHL. If only GHL-scheduled posts come back β confirmed dead-end. Circa can run this against a real location in minutes.
Keep the distinction: GHL stays exactly where it belongs β scheduling posts out for clients (and that's a genuine strength worth using). It is simply not a feed source in. The feed-display job still belongs to Behold (Phase 1) or the homegrown official-API build (Phase 2). This generalizes: any "can we use the tool we already pay for as a data source?" question should be answered by checking the upstream OAuth scopes that tool requested β not by reading its API catalog. The catalog tells you what it built; the scopes tell you what it's allowed to know.
B Β· Homegrown on the Official API (the legitimate build path)
This is Aspire's own integration on Meta's front door: our Meta App, our App Review approval, our token mgmt + cache on M3, our JSON feed serving all 10+ clients from feeds.madebyaspire.com. Zero bot-detection problem β same sanctioned traffic Behold sends. The only reason to defer is the App Review setup tax and the ongoing deprecation patching, both of which a vendor absorbs at <5 clients but become worth bringing in-house at scale.
What Meta's platform actually requires in 2026 (verified)
Two API surfaces β pick by login flow
Instagram API with Instagram Login
The canonical replacement for the dead Basic Display API. Native IG OAuth β does not require a linked Facebook Page. Lower friction for solo business owners.
Base: graph.instagram.com/v25.0/
Account type: Business or Creator only. Personal accounts have no API.
Instagram Graph API (via Facebook Login)
Used when the integration originates from a Facebook admin context. Richer data including comments + insights but requires the client to have an IG Business account linked to a Facebook Page.
Base: graph.facebook.com/v25.0/
Account type: IG Business + linked FB Page.
For a display-only feed, IG-with-IG-Login is the right choice β lower client onboarding friction (no Page-linking step) and the scope set is narrower.
Current scope names (canonical, post-Jan 27 2025)
| Scope (exact string) | Grants | Needed for display feed? |
|---|---|---|
| instagram_business_basic | Profile metadata + read media | Yes β this is the one |
| instagram_business_content_publish | Post photos/videos as the account | No |
| instagram_business_manage_comments | Comment moderation | No |
| instagram_business_manage_messages | DM view/manage/respond | No |
| pages_read_engagement | Read FB Page content + metadata | Only if displaying FB Page posts |
| pages_show_list | Enumerate user's Pages | Only if displaying FB Page posts |
Doc-confusion warning: Meta's /docs/permissions page still lists the old instagram_basic entry for Graph-API-via-Facebook-Login flows. The Jan 27 2025 deprecation specifically targeted the Instagram-Login OAuth scope set (which is the one we want). Don't blindly copy a 2024 blog post; verify against the live changelog.
Token model
- IG-with-IG-Login long-lived token: 60-day TTL. Refresh via
GET https://graph.instagram.com/refresh_access_token. Must be β₯24h old, not expired, holdinginstagram_business_basic. No refresh within 60 days = permanent death (client re-OAuth required). - FB Page tokens derived from long-lived user token via
/me/accounts: Still non-expiring as of 2026 (subject to standard invalidation: password change, user revoke, app suspension). - Implication for M3 cron: One refresh job per client every ~45 days. Cheap to run, but you must not miss the window. Defensive design: refresh at day 30, alert at day 45 if refresh failed.
Graph API release cadence (the deprecation treadmill)
- Current version: v25.0 (released Feb 18, 2026).
- Cadence: ~4 versions/year. Each version has a ~2-year sunset clock.
- v22.0 (Jan 21 2025) sunsets ~Jan 2027 β that's the practical refresh interval to budget for any homegrown integration. Plan an annual review + version bump.
- Notable 2025β2026 events: Dec 4 2024 Basic Display shutdown Β· Jan 27 2025 Instagram-Login scope rename Β· Apr 22 2026 new media engagement fields Β· Jun 1 2026 Instagram Audio API.
The App Review tax β Tech Provider path
If Aspire builds its own Meta app to serve 10 clients' feeds, we're a Tech Provider in Meta's framework. Meta's own app review doc has a literal selection: "I am a Tech Provider and my app serves multiple businesses." That triggers:
- Advanced Access required for every permission used (including
instagram_business_basic). - Business Verification via Meta Business Manager (official docs).
- One screencast per permission showing how the data is used in our product.
- At least 1 successful API call on the permission before submission.
- Privacy policy URL + data deletion instructions.
- Written use-case justification with captions/tooltips wherever the UI is non-obvious.
Per-round timeline
2β4 weeks per submission. Meta does not publish a guaranteed SLA; this is the converged third-party (Phyllo / Zernio, 2026) and community-reported norm.
Round count
First submission rejection is the norm. Tech Providers commonly cycle 2β3 rounds. Plan 6β10 weeks end-to-end for a single clean approval.
Topher-hours estimate
~12β20 hours of focused work over those 6β10 weeks: screencast prep, doc writing, business verification paperwork, submission iteration.
This is the one-time cost Behold spreads across thousands of customers. At 1β5 Aspire clients, paying $30/mo is a no-brainer trade. At ~25 clients, the math flips β see Section D.
Architecture sketch β Aspire's homegrown M3 build
# Service: feeds.madebyaspire.com (CF Worker β M3 origin)
#
# M3 Docker stack:
# βββ feeds-api (FastAPI Β· Node Express)
# β - GET /v1/feed/{client-slug} β JSON post array
# β - POST /v1/oauth/callback β store new client token
# βββ feeds-refresher (cron, every 24h)
# β - per client: if token age > 30d, refresh
# β - alert Aria if refresh fails (Linear OPS issue)
# βββ feeds-cache (SQLite)
# β - posts table: client_id, post_id, json blob, fetched_at
# β - tokens table: client_id, token, expires_at, refreshed_at
# βββ feeds-fetcher (cron, every 1h per client)
# - pulls latest 25 posts from graph.instagram.com
# - upserts into cache
#
# CF Worker (edge): cached JSON served from KV with 5-min TTL
# β keeps M3 cold-failure invisible to client sites
#
# Astro client site:
# const res = await fetch(
# 'https://feeds.madebyaspire.com/v1/feed/modern-maid'
# );
# const posts = await res.json();
Why a CF Worker in front of M3: M3's future uptime SLO isn't yet committed (per memory). The CF KV cache with 5-min TTL means if M3 goes dark, client sites continue serving the last known feed snapshot. We get M3's economics without M3's risk surface.
Per-client OAuth flow: Aspire-hosted /connect page β IG OAuth consent β callback stores long-lived token β done. Same flow Behold runs, just on our infrastructure.
Initial build
Meta-side: ~12β20 hrs of Topher's time over 6β10 weeks (App Review).
Code-side: ~16β24 hrs to ship feeds-api + feeds-refresher + CF Worker cache + onboarding page. Subagent-fan-out friendly.
Ongoing maintenance
~2β6 hrs/yr for Graph API version bumps + scope rename patching. Token refresh is automated; only fires alerts when a client revokes auth.
Marginal cost per client
$0/mo in vendor fees. ~15 min onboarding (run them through OAuth). Compared to ~$3β4/mo per client allocated Behold cost.
C Β· The Scraper Trap (do not confuse with Section B)
Why this section exists
The previous version of this doc bundled scraping with "homegrown Meta API" as twin options. They're opposites. Section B uses Meta's sanctioned front door β no bot detection problem ever. Section C β Playwright, instagrapi, the private mobile API β pretends to be a human browser and gets caught. Different problem, different risk, different verdict. Aspire never ships this for clients.
What you're actually fighting on the back door
Meta runs multi-layer bot detection on instagram.com. Playwright out of the box is fingerprinted and blocked quickly. Stealth plugins patch the most obvious signals (navigator.webdriver, missing plugins, HeadlessChrome user-agent) but can't address TLS fingerprinting (JA3/JA4), behavioral analysis, or advanced JS challenges.
The layers you're fighting:
- IP reputation: Residential IPs from a single home connection will be flagged after repeated scraping patterns. A proxy rotation pool helps but adds cost and complexity.
- Headless browser detection: WebGL renderer strings, font availability, timing patterns, and scroll behavior all leak "this is a bot."
- Login walls: Public profile pages are accessible without login, but Instagram progressively gates content for non-authenticated requests. Most profile pages now require login to see more than a few posts.
- Rate limiting: Aggressive patterns trigger IP-level 429s and temporary blocks.
Instagrapi (Python, 6K+ stars, June 2026 updates): Uses Instagram's private mobile API, not HTML scraping. Faster and more reliable than Playwright-based approaches β but requires login credentials (account security risk). The project itself warns: "Private API automation is fragile in production" β account trust, proxies, device state, and challenges can change independently. Internal tooling only, never client-facing.
Legal + ToS risk
Instagram's ToS explicitly prohibits scraping: "You can't attempt to create accounts or access or collect information in unauthorized ways."
The court ruling nuance: A 2024 California court ruled that Meta's ToS does not prohibit scraping of public data while logged out β CFAA's unauthorized access prohibition applies to circumventing authentication walls, not public-data access. This gives legal cover for non-authenticated scraping of public profiles.
Practical risk for Aspire: Legal risk is low-to-medium (scraping public posts, not private data). Operational risk is high β account bans, IP blocks, and scraper breakage from UI changes are the real threats. Instagram ships UI changes frequently; a scraper that worked in May may fail in July. Each break = client's feed goes blank = support ticket = Aspire's brand damaged.
The deeper Aspire-specific reason to refuse: our pitch to clients is "we run your stack so you don't have to babysit five vendors." Shipping them a scraper that breaks 3β5Γ/yr is the opposite of that promise. Path B (homegrown on official API) honors the pitch. Path C breaks it.
Initial build
8β16 hrs for a working MVP. Add 20+ hrs for retry logic, per-client session isolation, and admin endpoints.
Ongoing emergency maintenance
3β5 break events/yr at 2β8 hrs each = 6β40 hrs/yr unplanned. Unproductizable. Clients notice immediately.
Reliability ceiling
~85β92% uptime in good conditions. Section B (official API) sits at the same 99%+ uptime as Behold.
D Β· Recommendation + Graduation Trigger
Buy Behold.so Pro now. Build the homegrown M3 version when the graduation trigger fires.
This is two decisions, not one. The "buy now" is the right call for the next 12β18 months at Aspire's current client count. The "build later" is a real roadmap item we should put on the wall, not a hypothetical we hand-wave at.
Phase 1 Β· Buy Behold (Q3 2026 β graduation)
One Behold Pro account at $30/mo supports 15 sources (Instagram accounts) and 15 feeds. Comfortable headroom for the next 10 client wins. Each feed gets a unique JSON URL. Jaime adds a fetch call to the Astro component frontmatter:
---
// In any Astro component or page
const res = await fetch(
'https://feeds.behold.so/YOUR_FEED_ID'
);
const posts = await res.json();
---
{posts.map(post => (
<div class="feed-card">
<img src={post.sizes.medium.url}
alt={post.altText} />
<p>{post.prunedCaption}</p>
</div>
))}
Jaime has full CSS/class control over every element. The post object contains everything needed: media URLs (multiple WebP sizes), caption, hashtags, like/comment counts, and a color palette array for skeleton loading or accent colors.
Facebook clients: Add Curator.io Business ($54/mo) as a second vendor when the first client explicitly requests Facebook posts. Do not add upfront just in case.
Graduation trigger β when to start the homegrown M3 build
Open a CLI Linear ticket "Homegrown social feed pipeline on M3" and execute it when any one of these fires:
A Β· Cost crossover
Aspire crosses ~25 active client feeds. At that point Behold Platform plan ($60 + $0.45/feed beyond 50) starts catching up to the amortized build cost, and Aspire's vendor risk per client is meaningful enough to in-house.
B Β· Strategic surface
"Aspire owns the social pipeline" becomes part of the Concierge bundle or any agency-differentiated upsell. The moment Topher catches himself wanting to say "and we own the feed too" in a sales conversation, the build is worth more than $30/mo savings.
C Β· Forced migration
Behold ships a breaking change (price increase, API restructure, acquisition by someone we don't trust), or Meta deprecates something that Behold's wrapper hasn't caught up to and we end up debugging vendor JSON to ship a client fix. Forced migrations are the worst time to start a build β but they're also the moment when "we should own this" stops being abstract.
Earliest of the three fires. Don't wait for all three. The trigger is structural, not a prediction β when it fires, the answer is already "yes, build it." (Topher's stated lean is toward homegrown/M3 in principle. This is the frame for "in principle" β "in practice".)
Growth path
| Stage | Service | Monthly cost | Capacity / capability |
|---|---|---|---|
| 1β3 clients | Behold Starter | $10/mo | 3 IG feeds, test the integration |
| 4β15 clients | Behold Pro | $30/mo | 15 IG feeds, 5-min refresh, Klaviyo |
| FB requests arise | + Curator Business | +$54/mo | 15 IG + FB sources, API access |
| 15β25 clients | Behold Platform | $60 + $0.45/feed | Admin API, programmatic onboarding |
| ~25+ OR trigger B/C | Homegrown M3 | $0 vendor + CF Worker pennies | Owned pipeline; ~2β6 hrs/yr maintenance |
For Jaime specifically (Phase 1)
You fetch the JSON feed URL in the Astro component frontmatter. The response is a plain array of objects β no widget, no iframe, no Behold CSS on the page. You write your own card layout in standard HTML with Tailwind or whatever class system is on the project. Every post field is a data property you map: image URL, caption, likes count, timestamp. The feed auto-updates server-side at Behold β your Astro component just needs to fetch the URL and render. If you're building a static Astro site and want the feed to refresh without a rebuild, use Astro's server or hybrid rendering mode for that route, or use a lightweight client-side script that fetches the URL on page load (Behold has CORS whitelisting to make this safe). When Phase 2 (homegrown M3) ships, the only change for you is swapping the URL from feeds.behold.so/… to feeds.madebyaspire.com/v1/feed/…. We'll match the JSON shape so component code doesn't need to change.
E Β· Aspire Pricing Model
The goal is a clean productized add-on that (a) covers Aspire's cost, (b) is worth the value it delivers, and (c) fits naturally into the existing $250β650/mo retainer structure. Pricing stays the same across Phase 1 (Behold) and Phase 2 (homegrown M3) β clients shouldn't notice the migration, and Aspire's margin improves when we bring it in-house.
Aspire's cost basis (Phase 1, Behold)
| Line item | Cost | Notes |
|---|---|---|
| Behold Pro (up to 15 clients) | $30/mo | Shared Aspire account |
| Curator Business (if FB needed) | $54/mo (optional) | Add only when needed |
| Onboarding / setup per client | ~1β2 hrs Topher's time | Create feed, whitelist domain, Astro component |
| Monthly maintenance per client | ~10 min/mo | Monitoring, reconnect if client re-auths |
| Aspire vendor cost per client (10 clients) | ~$3β4/mo | $30 shared / 10 clients |
Phase 2 (homegrown M3) cost basis: $0/mo vendor + ~pennies/mo CF Worker requests. Per-client onboarding stays ~1 hr (OAuth flow). Topher invests ~12β20 hrs once on App Review + 16β24 hrs once on the build, then ~2β6 hrs/yr ongoing. Margin per client improves by $3β4/mo with no client-facing change.
Recommended client-facing pricing
Setup fee (one-time)
$150β250
Covers: connecting client's Instagram account, building the Astro feed component with brand-specific styling, testing cross-device, initial deployment. $150 for simple grid, $250 for styled layout with hover states, lightbox, etc.
Monthly add-on (recurring)
$25β35/mo
Covers: keeping the feed connected, monitoring, account cost allocation (vendor in Phase 1, infra in Phase 2), re-auth if needed. Sells as "Live social feed, always up-to-date" in the retainer line item.
How it fits the retainer: Present as a line item add-on, not a standalone product. A client on a $350/mo retainer adds "Social Feed" at +$25/mo = $375/mo. Expands the retainer without requiring a new sales motion. At 10 clients with the add-on, it's $250/mo revenue against ~$30β40 in hard costs (Phase 1) β ~$250/mo against pennies (Phase 2).
Facebook variant: If a client needs Facebook posts, add $10/mo (covering Curator in Phase 1, no marginal cost in Phase 2) and frame as "Multi-platform feed (Instagram + Facebook)" at $35β45/mo.
The sales pitch (for Jaime and Topher to use)
"Your Instagram feed on your website, styled to match your brand β not Instagram's widget. Posts update automatically. We handle all the technical connection. $150 to set it up, $25 a month to keep it running."
A non-technical business owner hears that and understands. The Behold-or-homegrown stack behind it is invisible β which is exactly right.
One client requirement: Business or Creator account
Any official-API path (Behold, Curator, homegrown β all of them) requires the client's Instagram account to be a Business or Creator account, not a personal account. If they're running a personal account for their business, they need to switch β it's free, takes 2 minutes in Instagram settings. Make this part of onboarding. Most active business owners are already on Business or Creator; rarely a blocker.
Verify before building β known gaps
These items should be verified before either Phase 1 launch or Phase 2 build:
- Behold's view counting with Astro SSR: Behold counts a "view" per request to the feed URL. If the Astro site uses server-side rendering and fetches on every page request, view counts will accumulate faster than with a cached static build. Confirm Behold's caching headers / CDN behavior for server-rendered sites. If client traffic is high, the Pro plan's 125K views/mo may be insufficient for a single client.
- Behold's carousel / Reel support: Carousel posts return a
childrenarray; Reels return a video URL. Confirm whether Behold surfaces the Reels video in the JSON or only the cover thumbnail, as this affects how Jaime renders video posts. Documentation indicatesmediaTypedistinguishes IMAGE / VIDEO / CAROUSEL_ALBUM but doesn't confirm whether the raw Reel video URL is in the response. - Curator.io's Facebook endpoint structure: Verified that Curator Business includes API access; specific endpoint format and field names for Facebook Page posts vs Instagram posts should be tested against a real Business account before committing to the integration pattern.
- Tech Provider App Review rejection rate: Meta does not publish round-count distribution. 2026 third-party guides (Phyllo, Zernio) report first-submission rejection as common but don't quantify. Topher should budget 2β3 rounds and 6β10 weeks end-to-end for Phase 2 planning; could be faster or slower.
- Behold Platform Admin API capabilities: Before upgrading to Platform, verify that the Admin API supports creating/managing feeds for different Instagram accounts programmatically, and review the per-feed pricing structure ($0.45/feed/mo above 50 feeds) against projected client count.
- Doc-confusion check for
instagram_basic: Meta's/docs/permissionsstill lists this scope for Graph-API-via-Facebook-Login flows. The Jan 27 2025 deprecation targeted the Instagram-Login OAuth scope set. Don't blindly grep for "instagram_basic" in 2024 blog posts; verify against the live changelog before submitting App Review.
Research + rewrite by Aria Β· June 8, 2026 (original) β June 9, 2026 (reframe) Β· Sources: developers.facebook.com (Instagram API with IG Login, Graph API changelog v22βv25, permissions reference, app review, long-lived tokens), behold.so, curator.io, embedsocial.com, juicer.io, getphyllo.com Instagram API guide 2026, zernio.com Graph API 2026, instagrapi GitHub.
Aspire Digital LLC internal planning document Β· cc.madebyotten.com/info/social-feed-integration-plan