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:
| Bucket | Purpose | Model Tier | Gemini Model |
|---|---|---|---|
| Awareness | Top-of-funnel, educational, entertaining | Flash | gemini-3-flash-preview |
| Trust | Social proof, case studies, testimonials | Flash | gemini-3-flash-preview |
| CTA | Conversion-focused, direct offers | Pro | gemini-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:
- awareness →
flash→gemini-3-flash-preview - trust →
flash→gemini-3-flash-preview - cta →
pro→gemini-3-pro-preview
Text Generation Models
| Endpoint | Model | Tier | Purpose |
|---|---|---|---|
| Brand voice extraction | gemini-3-pro-preview | Pro | Deep analysis of content samples |
| Generate post (CTA bucket) | gemini-3-pro-preview | Pro | High-quality conversion copy |
| Generate post (awareness/trust) | gemini-3-flash-preview | Flash | Fast, cost-effective content |
| Suggest angles | gemini-3-flash-preview | Flash | Quick angle ideation (3 per request) |
| Extract design config | gemini-3-flash-preview | Flash | Visual brand extraction from URL |
| Caption generation | gemini-3-flash-preview | Flash | Standalone caption helper |
| Hashtag generation | gemini-3-flash-preview | Flash | Tag 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 Case | Model |
|---|---|
| REST text/structured output | gemini-3-flash-preview |
| REST complex reasoning | gemini-3-pro-preview |
| REST image gen | gemini-3-pro-image-preview |
| Live API (voice) | gemini-3.1-flash-live-preview |
| Pipeline text LLM | gemini-3.1-flash-lite-preview |
Image Generation
| Endpoint | Model | Provider | Gateway |
|---|---|---|---|
| Post image generation | gpt-image-2 | Replicate or OpenAI Images | Yes (CF AI Gateway) |
Implementation in utils/gemini-image.js:
- Default path:
openai/gpt-image-2on Replicate when Cloudflare AI Gateway orREPLICATE_API_TOKENis configured - Fallback path: OpenAI's Images API directly with
gpt-image-2when onlyOPENAI_API_KEYis available - Both paths support first-party asset storage and auto-upload to GHL media library
- Decodes GPT image
b64_jsonresponse format
Requests requiring transparent backgrounds fall back to openai/gpt-image-1.5 because gpt-image-2 does not support transparent backgrounds on Replicate.
Carousel Support
Manual compose carousel prompts (e.g. "7-slide Instagram carousel") are inferred as multiple images:
- Each frame is generated and returned as
mediaUrls mediaUrlis 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.
| Field | Options | Default | What it does |
|---|---|---|---|
| Media mode | Designed / Raw / Mixed | Designed | Raw = every post is a real photo. Mixed = a set share of posts are real photos, the rest use design recipes. |
| Real photo share | 0–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 folders | folder list | the agent's reference folders | Which media-library folders hold the approved real photos and videos. |
| Photos per post | 1–10 | 1 | More than 1 posts a carousel of several real photos instead of one. |
| When the photo library runs out | Pause & notify / Reuse oldest | Pause & notify | Pause 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.
