Affinity Design
Agency Guide

Social Media Agent

Automated social media content creation with brand voice extraction, multi-bucket posting, and AI image generation

Overview

The Social Media Agent automates content creation and scheduling across social platforms. It extracts brand voice from existing content, generates posts across three content buckets, creates AI-generated images, and uploads assets to GoHighLevel's media library.

All AI calls route through Cloudflare AI Gateway for caching, rate limiting, observability, and centralized key management.

Setup

Environment Variables

CF_AI_GATEWAY_ACCOUNT_ID=your_account_id
CF_AI_GATEWAY_SLUG=your_gateway_slug
CF_AI_GATEWAY_TOKEN=your_gateway_token

# Image generation (at least one provider required)
IMAGE_GENERATION_PROVIDER=auto          # auto|replicate|openai
OPENAI_IMAGE_MODEL=gpt-image-2
REPLICATE_IMAGE_MODEL=openai/gpt-image-2
REPLICATE_API_TOKEN=your_replicate_token
OPENAI_API_KEY=your_openai_key

Cloudflare AI Gateway

Configure all providers in the Cloudflare AI Gateway dashboard (BYOK):

  • Google AI Studio — Gemini models
  • Replicate — Image generation (gpt-image-1.5)
  • OpenAI — Direct Images API fallback and text/STT fallback
  • Groq — Available for pipeline STT/LLM
  • Grok — Available

Helper utilities in utils/ai-gateway.js: getGeminiRestBaseUrl(), getReplicateBaseUrl(), buildGatewayAuthHeaders(), buildGatewayMetadataHeaders().

Brand Voice Extraction

Brand voice extraction uses Gemini 3 Pro for deep analysis of content samples to produce a full brand voice document. This document then guides all subsequent post generation to maintain consistency across buckets and platforms.

The extract design config endpoint also uses Flash-tier to extract visual brand identity from a website URL — colors, typography, and style preferences that inform image generation.

Content Buckets

Posts are organized into three buckets, each with automatic model routing:

BucketPurposeModel TierGemini Model
AwarenessTop-of-funnel, educational, entertainingFlashgemini-3-flash-preview
TrustSocial proof, case studies, testimonialsFlashgemini-3-flash-preview
CTAConversion-focused, direct offersProgemini-3-pro-preview

Content bucket determines model tier automatically. CTA posts use Pro-tier for higher-quality conversion copy; awareness and trust posts use Flash-tier for fast, cost-effective content.

Tier Strategy

The routing logic lives in utils/social-generate.js:

  • awarenessflashgemini-3-flash-preview
  • trustflashgemini-3-flash-preview
  • ctaprogemini-3-pro-preview

Text Generation Models

EndpointModelTierPurpose
Brand voice extractiongemini-3-pro-previewProDeep analysis of content samples
Generate post (CTA bucket)gemini-3-pro-previewProHigh-quality conversion copy
Generate post (awareness/trust)gemini-3-flash-previewFlashFast, cost-effective content
Suggest anglesgemini-3-flash-previewFlashQuick angle ideation (3 per request)
Extract design configgemini-3-flash-previewFlashVisual brand extraction from URL
Caption generationgemini-3-flash-previewFlashStandalone caption helper
Hashtag generationgemini-3-flash-previewFlashTag suggestions for a given topic

The table above reflects the default Gemini configuration. The text-generation provider for this agent can be switched per agency to OpenAI, Claude (Anthropic), GLM (z.ai), or Moonshot (Kimi K3) at Admin → Config → LLMS — this is a text-only pipeline (no vision calls), so all five providers are supported. Moonshot requires a MOONSHOT_API_KEY to be configured. Leave it on the default unless you have a specific reason to change it.

Quick Model Reference

Use CaseModel
REST text/structured outputgemini-3-flash-preview
REST complex reasoninggemini-3-pro-preview
REST image gengemini-3-pro-image-preview
Live API (voice)gemini-3.1-flash-live-preview
Pipeline text LLMgemini-3.1-flash-lite-preview

Image Generation

EndpointModelProviderGateway
Post image generationgpt-image-2Replicate or OpenAI ImagesYes (CF AI Gateway)

Implementation in utils/gemini-image.js:

  • Default path: openai/gpt-image-2 on Replicate when Cloudflare AI Gateway or REPLICATE_API_TOKEN is configured
  • Fallback path: OpenAI's Images API directly with gpt-image-2 when only OPENAI_API_KEY is available
  • Both paths support first-party asset storage and auto-upload to GHL media library
  • Decodes GPT image b64_json response format

Requests requiring transparent backgrounds fall back to openai/gpt-image-1.5 because gpt-image-2 does not support transparent backgrounds on Replicate.

Manual compose carousel prompts (e.g. "7-slide Instagram carousel") are inferred as multiple images:

  • Each frame is generated and returned as mediaUrls
  • mediaUrl is populated with the first frame for backward compatibility
  • Multi-image generation handles carousel frame sets automatically

Post Scheduling & GHL Media Library

Generated content and images are uploaded to the GoHighLevel media library for scheduling. The agent handles:

  • Post copy and caption generation
  • Image creation and upload
  • Hashtag suggestions
  • Scheduling across connected social accounts

All media assets are stored in GHL's first-party asset system, enabling direct scheduling without manual file transfers.

Raw Input Mode

Raw Input Mode ships a client's real, untouched photos instead of an AI-generated graphic. The caption is still written by AI, but the image itself is exactly the file the client uploaded — nothing renders or edits it. This is built for clients whose real photography (events, team candids, community shots) is more trustworthy to their audience than a designed graphic.

Configure it at Social agent → Config → Raw Input Mode. Like the rest of Brand Studio, a top-right Enable / Disable button turns it on or off and saves immediately; the Save button below it only commits the detail fields.

FieldOptionsDefaultWhat it does
Media modeDesigned / Raw / MixedDesignedRaw = every post is a real photo. Mixed = a set share of posts are real photos, the rest use design recipes.
Real photo share0–100%70%In Mixed mode, the share of posts that use a real photo. The split is exact (70% really means 70 out of every 100 posts), not a random roll that can drift over a short run.
Source foldersfolder listthe agent's reference foldersWhich media-library folders hold the approved real photos and videos.
Photos per post1–101More than 1 posts a carousel of several real photos instead of one.
When the photo library runs outPause & notify / Reuse oldestPause & notifyPause stops planning new raw posts and logs a warning until fresh photos are added — it never substitutes an AI graphic. Reuse oldest recycles the least-recently-used photo with a new caption.

Raw Input Mode is admin-only, the same as the rest of Brand Studio's visual setup — there's no client-portal control for it yet.

Photo selection favors the oldest unused photo first, so event photos tend to post in the order they happened, and no photo repeats until every photo in the source folders has posted once. Turning Raw Input Mode on for a client works best once their media library actually has a folder of real, approved photos to draw from — an empty or thin folder will exhaust quickly and pause posting.

Assigning Source Folders

Two places set the same source folder list, kept in sync automatically — use whichever is faster in the moment:

  • Media library → right-click a folder → Use as raw source. The folder gets a Raw source tag with a popover explaining what it does.
  • Brand Studio → Social Folders → click the camera icon on a folder row, next to the checkmark (style reference) and target (output) markers.

Tagging a folder as a raw source no longer locks it — you can still rename, move, or reorganize it like any other folder in the library.

Videos In Raw Input Mode

Source folders can hold videos as well as photos. A video always posts alone, never mixed into a photo carousel, and follows the same oldest-first, no-repeat-until-exhausted rule as photos. Video-only platforms (TikTok, YouTube) are still skipped for raw posts — raw videos go out on the feed platforms (Facebook, Instagram, LinkedIn).

The agent's own output folders (Social/Posted, Social/Drafts) can never be used as a raw source, even by accident — this stops a previously AI-generated post from being recycled and presented as a real, untouched photo.

Testimonial Quotes

The Testimonial bin in Brand Studio's reference bins used to hold only screenshots — useful to the image model when it designs a graphic, but invisible to the AI that writes captions, since it can't read text inside a picture. A "Social Proof" post could gesture at happy customers in the abstract but could never quote one by name.

The Testimonial bin now has a text half too. Open it and click Add a quote the agent can write with to type or paste a customer's exact words. A "N quotes" badge sits next to the screenshot count so you can see whether both halves are filled in.

Rules that keep this trustworthy:

  • Verbatim only. The agent may shorten a quote with an ellipsis; it may never reword it, combine two customers, or add a result the quote doesn't state.
  • No invented testimonials, ever. This is the one narrow, opt-in exception to that rule — with no quotes on file, nothing changes.
  • Quotes you type in yourself are approved automatically, since a human wrote them. Anything imported automatically in a later release will land unapproved, waiting for a person to sign off before it can appear in a post.

Platform Connection Gate

The agent cross-checks a client's configured target platforms against what's actually connected in GHL before generating anything. A lapsed OAuth token (Meta/Instagram expire fastest) can silently drop a platform from the GHL Social Planner — without this gate the agent would still generate a post that could never publish, indistinguishable from a real dead draft.

If a configured platform isn't connected, or its GHL status is Expired, the agent skips it for that cycle and logs a warn-level event in the agent's Logs tab naming the skipped platform(s), so you know to reconnect it under Social Accounts. The gate fails open: a transient GHL lookup error doesn't halt posting to every other platform, only disables the check for that cycle.

On this page