AWS Builder Center

Autonomous Instagram Automation with AWS Strands Agents, Nova Canvas & Bedrock

This article walks through a production-grade, fully autonomous Instagram posting system built on AWS Strands Agents SDK 1.0. The system uses a multi-agent architecture where four specialized AI agents Image, Analytics, Publisher, and Slack collaborate under a master Orchestrator agent to automatically generate 4K images, craft compelling captions, post to Instagram, and notify your team on Slack, every week, without any human intervention.

Introduction

Social media consistency is one of the hardest challenges for any brand or creator. Missing a post on Tuesday because you were in a meeting, or forgetting Thursday's drop because the team was heads-down on a release these small failures compound over time into lost reach, lower engagement, and diminishing returns.
 
This article walks through a production-grade, fully autonomous Instagram posting system built on AWS Strands Agents SDK 1.0. The system uses a multi-agent architecture where four specialized AI agents Image, Analytics, Publisher, and Slack collaborate under a master Orchestrator agent to automatically generate 4K images, craft compelling captions, post to Instagram, and notify your team on Slack, every Tuesday and Thursday, without any human intervention.
 
AWS Strands Agents, open-sourced in May 2025 and reaching 1.0 in May 2026, takes a model-driven approach: you define a prompt and a list of tools, and the LLM decides the execution path. There are no graphs to define, no node/edge configurations to maintain, and no router logic to debug. This makes it ideal for autonomous content workflows.

System Architecture

The system is composed of four specialized Strands agents orchestrated by a master agent, triggered automatically by Amazon EventBridge on a cron schedule:
 
AgentModelResponsibility
OrchestratorClaude 3.5
Sonnet
Master
coordinator runs the full workflow end to end
Image AgentNova Pro +
Nova Canvas
Analyzes raw
images, generates enhanced 4K versions
Analytics
Agent
Claude 3.5
Sonnet
Scans 30-day
post history, finds best time and topics
Publisher
Agent
(inline
tools)
Uploads media
to Instagram, publishes, logs to DynamoDB
Slack AgentClaude 3.5
Sonnet
Sends rich
Block Kit notifications on success or failure
 Scheduling with EventBridge
The system is triggered by Amazon EventBridge Scheduler on a cron expression that fires every Tuesday and Thursday at 14:00 UTC. The schedule invokes a Lambda function which instantiates the Orchestrator agent and passes it the current day context.
 
# EventBridge cron every
Tuesday and Thursday at 14:00 UTC
aws scheduler
create-schedule \
  --name instagram-auto-post \
  --schedule-expression "cron(0 14 ? *
TUE,THU *)" \
  --flexible-time-window '{"Mode":
"OFF"}' \
  --target '{
    "Arn":
"arn:aws:lambda:us-east-1:ACCOUNT:function:instagram-agent",
    "RoleArn":
"arn:aws:iam::ACCOUNT:role/scheduler-role"
  }'
 

Content Calendar in DynamoDB

Posts are queued in a DynamoDB table called instagram_posts. Each item stores the topic, a reference to the raw image in S3, and status tracking. The Orchestrator agent queries the table at runtime and picks up the next pending post.
 
# DynamoDB item schema
{
  "post_id":      "uuid-001",
  "status":       "pending",       # pending | published | failed
  "topic":        "AWS Cost Tips for
Developers",
  "media_s3_key":
"raw/aws-tips.jpg",
 
"scheduled_day":"TUESDAY",
  "caption":       null,
  "ig_media_id":   null,
  "published_at":  null,
  "reach_7d":      0,
  "likes_7d":      0
}
 

Image Agent: From Raw S3 to 4K

The Image Agent is the most technically complex component. It takes a raw image from S3, analyzes it using Amazon Nova Pro's vision capabilities, regenerates an enhanced version using Nova Canvas, then upscales it to 4K resolution using PIL's Lanczos algorithm before saving back to S3.
 

Step 1 Vision Analysis with Nova Pro

Nova Pro inspects the raw image and generates a rich, detailed description optimized for use as a Nova Canvas generation prompt. This includes subject matter, lighting conditions, color palette, mood, composition style, and background elements.
 
# Nova Pro vision
analysis
response =
bedrock.invoke_model(
    modelId="amazon.nova-pro-v1:0",
    body=json.dumps({
        "messages": [{
            "role":
"user",
            "content": [
                {"image":
{"format": "jpeg", "source":
{"bytes": b64}}},
                {"text":
"Describe this image in rich detail for AI image generation..."}
            ]
        }],
        "inferenceConfig":
{"max_new_tokens": 500}
    })
)
 

Step 2 Generation with Nova Canvas

Nova Canvas generates a premium-quality image at its maximum supported resolution. Key Nova Canvas constraints to be aware of: each side must be between 320 and 4096 pixels, divisible by 16; the aspect ratio must be between 1:4 and 4:1; and the total pixel count must be under 4,194,304 (approximately 4.19 megapixels). This means the effective maximum native output is 2048x2048 pixels.
 
Nova Canvas Resolution Limits
Maximum
native output: 2048x2048 (4.19MP). Each side: 320-4096px, divisible by 16.
Aspect ratio: 1:4 to 4:1. Total pixels: < 4,194,304. The system upscales
to 3840x2160 (4K UHD) post-generation using PIL Lanczos with an UnsharpMask
sharpening pass.
 
# Nova Canvas image
generation at max resolution
response =
bedrock.invoke_model(
   
modelId="amazon.nova-canvas-v1:0",
    body=json.dumps({
        "taskType":
"TEXT_IMAGE",
        "textToImageParams": {
            "text":
enhanced_prompt,
            "negativeText":
"blurry, low quality, watermark, distorted"
        },
        "imageGenerationConfig": {
            "numberOfImages": 1,
            "width": 2048,
            "height": 2048,
            "quality":
"premium",
            "cfgScale": 8.0,
            "seed": 42
        }
    })
)
 

Step 3 4K Upscaling with PIL Lanczos

After Nova Canvas generates the 2048x2048 image, PIL resizes it to 3840x2160 (4K UHD) using the Lanczos resampling filter the highest quality option available. An UnsharpMask filter is applied post-upscale to restore fine detail clarity that can soften slightly during enlargement.
 
# Upscale to 4K and save
to S3
img =
Image.open(io.BytesIO(base64.b64decode(base64_image)))
img_4k =
img.resize((3840, 2160), Image.LANCZOS)
img_4k = img_4k.filter(
    ImageFilter.UnsharpMask(radius=1.5,
percent=120, threshold=3)
)
output_key =
f"generated/4k/{post_id}.png"
s3.put_object(Bucket=BUCKET,
Key=output_key, Body=buffer)
 

Analytics Agent: Data-Driven Decisions

Rather than posting at a fixed time or with generic captions, the Analytics Agent scans the last 30 days of published posts in DynamoDB and extracts actionable intelligence: the posting hour that historically produces the highest average reach, the top three performing content topics, and the overall average reach per post.
 
This data is fed back to the Orchestrator agent, which uses it to inform caption generation writing content that gravitates toward proven high-performing topics and to guide timing recommendations for future scheduling improvements.
 
# Analytics summary
returned to Orchestrator
{
  "best_hour": 14,
  "top_topics": ["AWS Cost
Tips", "AI Tools", "Lambda Best Practices"],
  "avg_reach": 4200
}
 

The Orchestrator Agent

The Orchestrator is the master Strands agent. It coordinates the entire workflow using the Agent-as-Tool pattern introduced in Strands 1.0 each specialized agent is wrapped as a callable tool, making the system composable and independently testable.
 
The Orchestrator's system prompt defines the workflow as a numbered sequence of steps. Strands' model-driven architecture means Claude reasons through tool selection autonomously if the Image Agent fails, it can route to the failure notification path without explicit branching logic in code.
 
orchestrator = Agent(
   
model=BedrockModel(model_id="anthropic.claude-3-5-sonnet-20241022-v2:0"),
    system_prompt="""
    Every Tuesday and Thursday, run this
workflow:
    1. fetch_pending_post       → get topic and raw S3 image key
    2. run_analytics_agent      → get best hour, avg reach, top topics
    3. run_image_agent          → enhance raw image to 4K
    4. Generate caption         → 150-200 words, 10-15 hashtags
    5. publish_to_instagram     → upload and publish
    6. run_slack_agent          → notify team (success or failure)
    """,
    tools=[
        fetch_pending_post,
        run_analytics_agent,
        run_image_agent,
        publish_to_instagram,
        run_slack_agent,
    ]
)
 

Publishing to Instagram

Instagram publishing uses the Meta Graph API v19.0 in a two-step process: first create a media container by providing a presigned S3 URL and caption, then publish the container using its creation ID. The presigned URL approach keeps S3 private while allowing Meta's servers to fetch the image temporarily.
 
All credentials the long-lived Instagram access token, the IG User ID, and the S3 bucket name are stored in AWS Secrets Manager and retrieved at runtime. They are never hardcoded or passed through environment variables.
 
# Step 1: Create media
container
r1 = requests.post(
   
f"https://graph.facebook.com/v19.0/{ig_user_id}/media",
    params={
        "image_url":
presigned_s3_url,
        "caption":
generated_caption,
        "access_token": token
    }
)
creation_id =
r1.json()['id']
 
# Step 2: Publish
r2 = requests.post(
   
f"https://graph.facebook.com/v19.0/{ig_user_id}/media_publish",
    params={"creation_id":
creation_id, "access_token": token}
)
ig_media_id =
r2.json()['id']
 

Slack Notification Agent

The Slack Agent closes the loop by sending a rich Block Kit notification to a designated Slack channel after every workflow run. On success, the card includes the post topic, timestamp, IG Media ID, a caption preview, and the full analytics summary. On failure, it sends an urgent alert with the error details and a pointer to CloudWatch logs.
 
A separate EventBridge rule fires every Sunday to trigger a weekly digest a consolidated summary of all posts from the week with reach and likes metrics for quick performance review.
 
Slack Notification Contents (Success)
Post topic |
Published timestamp | IG Media ID | Post ID | Caption preview (200 chars) |
Best posting hour (UTC) | Average reach (30-day) | Top 3 performing topics |
4K image S3 key
 

Security & IAM

The Lambda execution role requires the following minimum permissions. Following the principle of least privilege, all resource ARNs should be scoped to specific resources rather than wildcards in production.
 
# Required IAM
permissions for the Lambda role
{
  "Action": [
    "dynamodb:Query",
    "dynamodb:Scan",
    "dynamodb:UpdateItem",
    "dynamodb:PutItem",
    "s3:GetObject",
    "s3:PutObject",
   
"secretsmanager:GetSecretValue",
    "bedrock:InvokeModel"
  ],
  "Resource": [
   
"arn:aws:bedrock:*::foundation-model/amazon.nova-canvas-v1:0",
   
"arn:aws:bedrock:*::foundation-model/amazon.nova-pro-v1:0",
   
"arn:aws:bedrock:*::foundation-model/anthropic.claude-3-5-sonnet*"
  ]
}
 

Cost Breakdown

The system runs twice a week (104 times per year) with the following approximate cost per run:
 
ServiceUsage per
Run
Approx. Cost
Nova Canvas1 image @
premium quality
~$0.08
Nova ProVision
analysis (~500 tokens)
~$0.002
Claude 3.5
Sonnet
Caption +
orchestration
~$0.01
Lambda~60s
execution, 1GB RAM
~$0.001
S31 x 4K PNG
(~8MB)
~$0.0002
DynamoDB~10
reads/writes
< $0.001
Total per run~$0.09–$0.12
Total per
year (104 runs)
~$10–$13
 

Adding Posts to the Queue

Adding a new post to the automation queue is a single DynamoDB put_item call. The agent picks it up automatically on the next scheduled Tuesday or Thursday run.
 
import boto3, uuid
from datetime import
datetime
 
table =
boto3.resource("dynamodb").Table("instagram_posts")
 
table.put_item(Item={
    "post_id":       str(uuid.uuid4()),
    "status":        "pending",
    "topic":         "5 AWS Lambda Best Practices
for 2026",
    "media_s3_key":  "raw/lambda-tips.jpg",
    "scheduled_day":
"THURSDAY",
    "created_at":    datetime.utcnow().isoformat()
})
 

Installation

pip install
strands-agents \
            strands-agents-tools[slack] \
            boto3 \
            requests \
            pillow
 

Conclusion

This system demonstrates what becomes possible when you combine AWS Strands Agents' model-driven orchestration with Bedrock's foundation models. The entire multi-agent pipeline image enhancement, analytics, publishing, and team notification runs autonomously with under 200 lines of meaningful application code per agent.
 
Key architectural takeaways: use DynamoDB as a lightweight content calendar and audit log; use the Agent-as-Tool pattern to keep agents independently testable; store all secrets in Secrets Manager; and let the LLM handle branching logic through its system prompt rather than explicit conditional code.
 
The total infrastructure cost is approximately $10-13 per year for twice-weekly posting a compelling case for fully agentic content automation on AWS.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article