Install
openclaw skills install instagram-account-operationsOperating doctrine for Instagram account automation — careful creator + business pattern via Meta Business Suite, role separation, action-block awareness (24h/7d/permanent), comment + DM ops (Playwright click + type + Enter), reply qualification, hashtag-shadowban discipline, and recovery. Use this for any scheduled IG activity (cron, agent, recurring task) where account safety and Reels reach matter more than raw output.
openclaw skills install instagram-account-operationsThis skill is the operating doctrine for every Instagram automation run on a brand, professional or personal account.
The goal is not to comment fast. The goal is to operate Instagram like a careful, helpful human contributor: stable browser, correct context (Meta Business Suite), useful action, no action block, no shadowban risk.
Drop-in for any niche (legal, medical, software, finance, creator, ecommerce). Replace the placeholders in section 0 with your own values.
Before running anything, fill these placeholders in your local copy or your agent's memory:
| Placeholder | Example | Your value |
|---|---|---|
<BRAND_NAME> | "Acme Studio" | — |
<BRAND_DOMAIN> | "acme.studio" | — |
<IG_HANDLE> | "@acmestudio" | — |
<META_BUSINESS_ID> | numeric ID from business.facebook.com → Settings | — |
<META_ASSET_ID> | numeric ID of the IG account asset in MBS | — |
<BROWSER_PROFILE> | "instagram-live" | — |
<BROWSER_PORT> | "18802" | — |
<NICHE_KEYWORDS> | "lost license OR speeding ticket" | — |
<PRIMARY_CTA> | "WhatsApp / form / app — pick ONE" | — |
<WORKSPACE_DIR> | "~/.openclaw/workspace/instagram-<brand>" | — |
All shell snippets below assume an OpenClaw browser CLI bound by CDP, but the doctrine works with any browser-automation stack (Playwright, Puppeteer, Chrome MCP). Swap the CLI calls for your own.
If your agent reads config from YAML, drop this in <WORKSPACE_DIR>/config.yaml:
brand:
name: <BRAND_NAME>
domain: <BRAND_DOMAIN>
instagram:
handle: <IG_HANDLE>
account_type: business | creator # business strongly recommended for MBS access
browser_profile: <BROWSER_PROFILE> # e.g. "instagram-live"
browser_port: <BROWSER_PORT> # e.g. 18802
meta_business_suite:
business_id: <META_BUSINESS_ID>
asset_id: <META_ASSET_ID>
base_url: https://business.facebook.com/latest/inbox
discovery:
niche_keywords: <NICHE_KEYWORDS>
cta:
primary: <PRIMARY_CTA> # one channel only
workspace:
dir: <WORKSPACE_DIR>
alerts:
channel: telegram | slack | discord
webhook: <YOUR_WEBHOOK_URL>
schedule:
timezone: Europe/Paris
windows:
dm_check: "*/15 9-22 * * *" # every 15 min
comment_check: "10,25,40,55 9-22 * * *" # offset to avoid collision
browser_health: "0 * * * *"
daily_recap: "21:00"
| Stack | Skill install path |
|---|---|
| Claude Code | ~/.claude/skills/instagram-account-operations/ |
| OpenClaw | ~/.openclaw/skills/instagram-account-operations/ |
| ClawHub-published | one-click install via clawhub.ai |
| Cursor / Copilot CLI | drop SKILL.md into your project's .cursorrules or AGENTS.md |
| Any LLM agent reading markdown rules | concatenate SKILL.md into your system prompt |
Doctrine: EVERYTHING goes through business.facebook.com. Never automate against instagram.com directly.
Why:
click + type + press Enter works out of the box.<PRIMARY_CTA>.instagram.com's "redirect to /direct/inbox/" bug.A single browser profile per account:
<BROWSER_PROFILE> (CDP direct, attached to http://127.0.0.1:<BROWSER_PORT>)The IG account must be logged into Meta Business Suite in this profile and have an Asset assigned to a Business — otherwise the URLs below will 404 or redirect to a setup wizard.
openclaw browser --browser-profile <BROWSER_PROFILE> status
openclaw browser --browser-profile <BROWSER_PROFILE> navigate https://business.facebook.com/latest/inbox/all/?business_id=<META_BUSINESS_ID>&asset_id=<META_ASSET_ID>
openclaw browser --browser-profile <BROWSER_PROFILE> snapshot --limit 200
| Tab | URL fragment |
|---|---|
| All messages (IG DMs + FB Messenger DMs) | /latest/inbox/all?asset_id=<META_ASSET_ID>&business_id=<META_BUSINESS_ID> |
| Messenger only (FB DMs) | /latest/inbox/messenger?asset_id=<META_ASSET_ID>&business_id=<META_BUSINESS_ID> |
| Instagram DMs only | /latest/inbox/instagram_direct?asset_id=<META_ASSET_ID>&business_id=<META_BUSINESS_ID> |
| Instagram comments | /latest/inbox/instagram?asset_id=<META_ASSET_ID>&business_id=<META_BUSINESS_ID> |
| Facebook comments | /latest/inbox/facebook?asset_id=<META_ASSET_ID>&business_id=<META_BUSINESS_ID> |
This skill covers IG-specific concerns; for FB-specific doctrine (Pages, groups, page moderation), see the companion facebook-account-operations skill.
ig-postAccount cockpit (acting as the brand). Use for:
Default page: MBS inbox/all.
ig-engageDiscovery. Use for:
instagram.com, but DO NOT act from there).Default page: MBS inbox/instagram (comments tab).
ig-stealthQuiet maintenance. Use for:
Default page: MBS dashboard.
ig-post = act as the account via MBS.ig-engage = discover and qualify, NEVER act outside MBS.ig-stealth = maintain and observe.inbox/all.openclaw browser --browser-profile <BROWSER_PROFILE> status
openclaw browser --browser-profile <BROWSER_PROFILE> navigate "https://business.facebook.com/latest/inbox/all/?business_id=<META_BUSINESS_ID>&asset_id=<META_ASSET_ID>"
openclaw browser --browser-profile <BROWSER_PROFILE> snapshot --limit 60
Check:
status is stopped: report and stop.Never relaunch Chrome from inside a cron.
Instagram does not have karma; it has action blocks — a tiered penalty system:
Always read <WORKSPACE_DIR>/memory/ig-state.md at start (last line = current phase).
| Action | Frequency that triggers a block |
|---|---|
| Follow / unfollow | > 50/day or > 200/week |
| Comment on others' posts | > 30/hr or > 200/day |
| DMs to non-followers (proactive) | > 10/day on a young account |
| Liking | > 60/hr |
| Posting | > 5 posts/24h |
A block lasts 24 h (warning), 7 d (second offense), or permanent (third+). The thresholds tighten on Phase A accounts.
You can force Phase B by appending YYYY-MM-DD - phase=B (manual override) to ig-state.md. Use only if the account is grandfathered (verified business, long history, no warnings). Document in ig-learnings.md.
A DM or comment is repliable only if all of:
ig-reply-log.md).If any check fails: skip. Document why in the recap.
Default action: skip silently. A Reel share without a question is usually a forward to friends; replying creates noise and confuses the conversation.
If the user appears in ig-clients-known.md: reply with empathy, do not paste any link, redirect to the standard support channel (NOT <PRIMARY_CTA> which is for prospects).
DM reply (any length, but ≤ 700 chars stays human):
[Acknowledge the situation in 1 sentence, neutral tone.]
[General framework in 2-3 short paragraphs.]
[Concrete next step — point to <PRIMARY_CTA>. ONE channel only.]
Comment reply (≤ 200 chars, prefix with @username to target the parent comment):
@username [contextual acknowledgement]. [Indirect signal — "DM us" or "form on profile"].
[brackets] left in it (final read-through is mandatory).<PRIMARY_CTA>'s own link AND it is the second message in the conversation (Meta's link-preview takes 1-2 s; if pasted as the first interaction, IG marks it as spam).<PRIMARY_CTA>). Never a bit.ly / tinyurl / shortener — IG marks shorteners as spam.Out of scope for the live reactive crons. Recommended rhythm for a Phase B account:
Hashtag discipline (Reels + posts):
<WORKSPACE_DIR>/memory/ig-hashtag-state.md registry monthly for shadowbanned tags.| Action | Phase A limit | Phase B limit |
|---|---|---|
| DMs handled (inbound replies) per 24 h | 20 | 60 |
| DMs handled per cron run | 4 | 8 |
| Comment replies handled per 24 h | 30 | 100 |
| Comment replies handled per cron run | 5 | 10 |
| Outbound DMs / day (to non-followers) | 0 | 5 |
| Follows / day | 5 | 20 |
| Unfollows / day | 5 | 20 |
| Likes per hour | 30 | 60 |
| Actions in same conversation | min 60 s apart | min 30 s apart |
| Actions globally | min 30 s apart | min 15 s apart |
Quota tracking: read ig-reply-log.md at start of every run, count entries in the last 24 h, abort early if quotas already met.
| Avoid | Use instead |
|---|---|
| "Check link in bio" repeated | (mention bio at most once per conversation) |
<BRAND_NAME> more than once per reply | (max one mention) |
| "DM me", "WhatsApp me", "click here" stacked | (one CTA, one channel — <PRIMARY_CTA>) |
| Phone numbers, emails | (never in comment bodies; OK in DM tail if user explicitly asked) |
| Emojis in regulated / sober niches | (drop them) |
| All caps for emphasis | (use sparingly) |
| Shorteners (bit.ly / tinyurl) | (use the full canonical URL) |
6 actions in 10 min → rate limit on that role.
Reactive DM + comment ops run inside MBS exclusively. The flow below is validated end-to-end.
URL: https://business.facebook.com/latest/inbox/all?business_id=<META_BUSINESS_ID>&asset_id=<META_ASSET_ID>
all tab. Wait 5 s for the conversation list to render.[contenteditable='true'] or [aria-label*='Reply'], [aria-label*='Répondre'].
e. Type the message via Playwright type (or evaluate with document.execCommand('insertText', false, msg) ONLY if contenteditable is a vanilla React-controlled input — verify first).
f. Press Enter to send. Do NOT click "Send" — there are visual duplicates of the send button and a Playwright click sometimes lands on the wrong one. Enter is unambiguous.Messenger tab and to the Instagram tab in turn to catch any FB-only or IG-only inboxes that didn't surface in all.URL: https://business.facebook.com/latest/inbox/instagram?business_id=<META_BUSINESS_ID>&asset_id=<META_ASSET_ID>
The comments tab is less stable than DMs — see "Known issue" below.
@username your reply (the @username prefix targets the parent comment without clicking "Reply").Clicking the "Reply" affordance under a comment navigates the right pane to a different post (Meta's SPA bug, present in 2025-2026). The validated workaround is @username prefix + page-level textarea + send-arrow click — described above.
If you must produce a true nested reply (rare): open the post URL on instagram.com in a separate ig-engage tab, reply there manually, then mark the conversation done in ig-reply-log.md. Do not script the instagram.com reply path — Instagram's anti-automation is much tighter than MBS.
| Element | Selector |
|---|---|
| DM textbox | [contenteditable='true'] or [aria-label*='Reply'], [aria-label*='Répondre'] |
| DM send (preferred) | press Enter |
| Comment textarea | textarea[placeholder*='comment'], textarea[placeholder*='commentaire'] |
| Comment send | the SVG arrow button to the right of the textarea — [aria-label*='Send'], [aria-label*='Envoyer'] |
| Conversation tile | text=<user's display name> |
| Tab "Messenger" | text=Messenger |
| Tab "Instagram" | text=Instagram (the DMs tab) |
| Tab "Commentaires Instagram" | text=Instagram (in comments URL — same string, different URL) |
| Unread filter chip | text=Unread, text=Non lu |
| Code | Meaning | Recap action |
|---|---|---|
| 0 | Replies sent, verified | status: ok |
| 1 | Fatal error (selector missing, MBS error toast) | status: error, attach screenshot |
| 2 | "Action blocked" / "Try again later" toast | status: blocked, flip the role to Phase A pause |
| 3 | Session expired (login form rendered) | status: blocked, alert user |
| 4 | Comment "Reply" caused page navigation (known bug — see above) | status: partial, log for manual review |
@username workaround.Reply / Répondre, Send / Envoyer — maintain a label map and try both in selectors.all, messenger, instagram_direct), wait ≥ 3 s after switching — MBS re-fetches the conversation list and clicking too early lands on stale tiles.Non Lu / Unread filter chip is sometimes mis-clicked: it has a transparent overlay. Snapshot before clicking.File: <WORKSPACE_DIR>/memory/ig-state.md
For each day:
File: <WORKSPACE_DIR>/memory/ig-clients-known.md
For each existing client:
Update at the end of every run.
| Issue | Action |
|---|---|
status: stopped | Report, stop. |
| Login form rendered on MBS | Session expired, alert, stop. |
| "Reauthenticate to manage this asset" banner | Same as login expired. |
| "Action blocked — try again later" toast | Flip the role to Phase A pause for 24 h. Alert. |
| "Please verify it's you" / re-captcha | Stop. Never auto-solve. Alert for manual login. |
| MBS shows "Something went wrong" generic error | Refresh once. If persists, stop and alert. |
| Comment "Reply" click navigated to wrong post | Mark exit 4, fall back to manual via instagram.com. |
| Followers drop > 5 % overnight | Likely shadowban — flip to Phase A, alert. |
| Two consecutive comments removed within < 10 min of post | Auto-freeze comment cron for 6 h. |
At the end of each cron:
Alert channel — final run message:
[Job name] — [status: ok|partial|blocked|skipped]
DMs handled: [N or "—"]
Comments handled: [N or "—"]
Hot leads: [list short OR "—"]
Phase: [A|B]
Blockers: [text OR "—"]
Next action: [1 line]
Memory — append to <WORKSPACE_DIR>/memory/ig-recaps.md:
## YYYY-MM-DD HH:MM TZ — <job-id> — status: <status>
- Job: <description>
- Phase: A|B
- DMs sent: <N>
- Comments sent: <N>
- Hot leads: <list or "—">
- Blockers: <text or "—">
- Next useful action: <1 line>
Located at: <WORKSPACE_DIR>/memory/
| File | Purpose | Update cadence |
|---|---|---|
ig-recaps.md | Per-run logs | Every cron run |
ig-post-log.md | Reels + carousels + stories (URL, type, date, reach) | Each posting run |
ig-reply-log.md | DM + comment replies sent | Each reply pass |
ig-state.md | Daily phase + followers + warning flags | Daily Metrics Recap |
ig-hashtag-state.md | Per-hashtag reach + shadowban check | Weekly |
ig-clients-known.md | Existing clients to NEVER pitch | Ad hoc |
ig-ideas.md | Content backlog | Weekly Planning |
ig-learnings.md | Patterns (what reached, what got removed) | Weekly + ad hoc |
ig-alerts-sent.md | Anti-doublon hot-lead alerts | Each alert |
@drsmithlegal > @bestlawyerinparis).<PRIMARY_CTA> link. No emojis, no flag salad in regulated niches.<PRIMARY_CTA>.When the Daily Metrics Recap detects (account_age_days ≥ 30) AND (followers ≥ 500) AND (last_action_block_days_ago > 30):
ig-state.md: YYYY-MM-DD - phase=A - PHASE_B_THRESHOLD_REACHED.🎉 IG account ready for Phase B — review and flip outbound crons manually.Action Status (MBS → Settings → Account Status). Any "warning" reverts to Phase A.Better silence than spam. Better a blockage report than a fake success.
<META_BUSINESS_ID> and <META_ASSET_ID> extracted (open MBS, copy from the URL).<PRIMARY_CTA> link.http://127.0.0.1:<BROWSER_PORT> and logged into facebook.com (the MBS gate).inbox/all renders the conversation list (no login form, no setup wizard).<WORKSPACE_DIR>/memory/ exists with the 9 memory files.Init memory:
mkdir -p "<WORKSPACE_DIR>/memory" && cd "$_" && touch ig-recaps.md ig-post-log.md ig-reply-log.md ig-state.md ig-hashtag-state.md ig-clients-known.md ig-ideas.md ig-learnings.md ig-alerts-sent.md
Q: Do I need OpenClaw to use this skill? A: No. OpenClaw browser CLI is the example stack — the doctrine works with Playwright (Node or Python), Puppeteer, Chrome MCP, or any CDP-capable tool.
Q: Can I just use the Instagram Graph API?
A: Partially. The Graph API covers instagram_basic, instagram_manage_messages, instagram_manage_comments — if you have an approved app, you can build a more robust webhook-based flow. The doctrine in this skill is the fallback for accounts not yet approved for Graph API access, or for cases where MBS UI features are needed (labels, prospect stages, link previews).
Q: What about multi-account?
A: Clone the workspace dir per account. Use a separate browser profile + port. Each IG account must have its own Meta Business asset — you can manage multiple assets from one MBS, but they have distinct <META_ASSET_ID> values.
Q: My account got an action block during testing. What now?
A: Stop everything. Flip to Phase A. Manual usage only for 7-14 days. Document in ig-learnings.md the exact last 20 actions. Do NOT appeal automatically.
Q: Does the doctrine cover Reels Ads / Boost / Shopping? A: No. This skill is for organic + reactive ops only. Ads have a separate dashboard and a separate (different) sanction pattern.
Q: What's the most common reason this skill's crons get flagged? A: Same opening phrase across replies. Vary the first 1-2 words every time. The second most common: replying within 30 s of a comment landing — wait ≥ 2 min.
Q: What if my account is suspended (not just action-blocked)?
A: Stop everything. Do not appeal automatically — Instagram's appeal flow is sensitive to repeated automated submissions. Manual review only. Document the exact last 20 actions before the suspension in ig-learnings.md.