ワンクリックで
facebook-automation
Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | facebook-automation |
| description | Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows |
| allowed-tools | browser_navigate browser_click browser_type browser_fill_form browser_get_snapshot browser_screenshot browser_wait browser_navigate_back browser_get_page_info browser_hover browser_press_key browser_evaluate browser_scroll write_todos browser_extract_posts |
Automation guide for Facebook web interface - posts, privacy settings, interactions, and navigation.
If you received a Success Plan with working_selectors, try those patterns first.
STOP! If you're about to use browser_evaluate to click, DON'T.
This is the #1 cause of agent failures. browser_evaluate for clicking:
If browser_evaluate returns null ONCE:
browser_get_snapshot()browser_click(ref="eXX", force=True) with ref from snapshotAfter ANY click, type, or navigation:
browser_get_snapshot() to get fresh refse78) now points to a DIFFERENT elementExample of what goes wrong:
browser_get_snapshot()
# e78 = button "What's on your mind?"
browser_click(ref="e78", force=True) # Opens dialog
browser_click(ref="e78", force=True) # WRONG! e78 is now "Live video"!
Correct pattern:
browser_get_snapshot()
# e78 = button "What's on your mind?"
browser_click(ref="e78", force=True)
browser_get_snapshot() # GET FRESH REFS!
# Now e78 might be something completely different
# e42 = button "Friends" (privacy button)
browser_click(ref="e42", force=True)
If you clicked to open a dialog but snapshot doesn't show dialog elements:
browser_wait(time=2) - give React time to renderbrowser_get_snapshot() - check againforce=TrueIf same action fails 2 times:
browser_evaluate returns null 2x → Use browser_click with refDO NOT repeat the same failed pattern more than 2 times.
The browser_get_snapshot() tool returns a YAML accessibility tree using Playwright's locator.aria_snapshot() API:
- navigation "Facebook":
- link "Home" [ref=e0]
- button "Search" [ref=e1]
- main:
- button "What's on your mind?" [ref=e15]
- dialog "Create post":
- textbox "What's on your mind?" [ref=e20]
- button "Public" [ref=e21]
- button "Post" [ref=e25]
Format explanation:
role "accessible name" [ref=eN] - Each element with unique refbutton, link, textbox, checkbox, radio, heading, dialog, etc.[checked], [disabled], [expanded], [pressed=true]BEFORE ANY ACTION:
# OBSERVE - Get FRESH snapshot
browser_get_snapshot()
# THINK - MUST explicitly list elements you see:
# I see in this snapshot:
# - button "Close composer dialog" [ref=e31] ← NOT what I want!
# - button "Friends" [ref=e42] ← This is the privacy button (shows current setting)
# - button "Photo/video" [ref=e43] ← NOT privacy
# - button "Post" [ref=e50] ← Submit button
#
# I need to change privacy. The button showing "Friends" is ref=e42.
# ACT - Use the ref from THIS snapshot
browser_click(ref="e42", force=True)
# VERIFY - Get NEW snapshot (previous refs are now stale!)
browser_wait(time=1)
browser_get_snapshot() # REQUIRED after every action
# Now analyze the NEW refs before next action
| Rule | Why |
|---|---|
| Get fresh snapshot after EVERY action | Refs become stale immediately |
Always force=True on clicks | Facebook has invisible overlays |
browser_wait(time=1-2) after actions | React needs time to re-render |
| List elements before clicking | Prevents clicking wrong button |
| Complete ALL dialog steps | Selecting ≠ confirming |
| Verify with snapshot before "done" | Task isn't complete until verified |
| Read button names carefully | "Close composer" ≠ privacy button! |
| Max 2 retries per approach | If it fails twice, try different strategy |
Get ARIA accessibility snapshot with element refs.
browser_get_snapshot()
Output: YAML accessibility tree with [ref=eN] markers on each element.
Click element using ref (preferred) or selector.
# Using ref (RECOMMENDED)
browser_click(ref="e42", force=True)
# Using selector (fallback)
browser_click(selector="button=Post", force=True)
Always use force=True on Facebook.
Type text into an input field.
# Using ref
browser_type(ref="e23", text="Hello world")
# Using selector
browser_type(selector="div[contenteditable='true'][role='textbox']", text="Hello")
Wait for UI updates after actions.
browser_wait(time=1) # 1 second for simple actions
browser_wait(time=2) # 2 seconds for navigation/dialogs
Press keyboard keys.
browser_press_key(key="Enter")
browser_press_key(key="Escape")
Hover to reveal hidden UI (like reactions).
browser_hover(ref="e28")
⚠️ WRONG SELECTORS (Don't Use):
article - Facebook doesn't use semantic HTML articlesdiv[role="article"] - Posts don't have this ARIA rolediv[data-ad-preview="message"] - Only works for ads, not organic posts✅ CORRECT SELECTORS FOR FACEBOOK POSTS (2025):
# Feed container
"div[role='feed']"
# Individual posts
"div[data-testid='feed_story']"
# Post content elements
"div[data-testid='post_message']" # Post text
"a[data-testid='story_author_link']" # Author link
"span[data-testid='story_timestamp']" # Timestamp
"img[data-testid='story_photo']" # Post images
"div[data-testid='feed_loading_indicator']" # Loading spinner (lazy load)
# Use getByRole pattern (most stable against DOM changes)
page.get_by_role("feed") # Feed container
page.get_by_role("article") # Individual posts (if present)
page.get_by_role("link", name="author") # Author links
page.get_by_role("img") # Images
# 1. Get snapshot
browser_get_snapshot()
# 2. Parse snapshot YAML to find post refs
# Posts appear as "generic" or custom roles with accessible names
# 3. Use refs for precise interaction
browser_click(ref="e42", force=True)
# Step 1: Navigate to feed
browser_navigate(url="https://www.facebook.com")
browser_wait(time=2)
# Step 2: Get initial snapshot
browser_get_snapshot()
# Step 3: Scroll to load more posts (lazy loading)
browser_scroll(direction="down", amount=500)
browser_wait(time=2) # Wait for lazy load to complete
# Step 4: Get fresh snapshot with new posts
browser_get_snapshot()
# Step 5: Extract posts using correct selectors
posts = await page.locator("div[data-testid='feed_story']").all()
# Step 6: Parse each post for content
for post in posts:
author = post.locator("a[data-testid='story_author_link']")
text = post.locator("div[data-testid='post_message']")
timestamp = post.locator("span[data-testid='story_timestamp']")
# Check if more posts are loading
loading = await page.locator("div[data-testid='feed_loading_indicator']").count() > 0
# Scroll until no new content appears
prev_count = 0
while True:
await page.locator("div[data-testid='feed_story']").count() == prev_count:
browser_scroll(direction="down", amount=500)
browser_wait(time=2)
current_count = await page.locator("div[data-testid='feed_story']").count()
if current_count == prev_count:
break # No new posts loaded
prev_count = current_count
div[data-testid='feed_story']div[role='feed']browser_get_snapshot()button="Post", text="Like"Priority order (most reliable first):
ref="e42" - From snapshot (BEST)button=Name - Buttons by accessible nameradio=Option - Radio buttons in dialogs[aria-label="Label"] - By aria-labelrole=textbox - For input fields| Element | Selector |
|---|---|
| Open composer | button=What's on your mind? |
| Text input | div[contenteditable='true'][role='textbox'] or role=textbox |
| Post button | button=Post |
| Next button | button=Next |
| Done button | button=Done |
⚠️ CRITICAL: Privacy button has DYNAMIC name
The privacy button's accessible name includes the current setting PLUS dynamic friend names:
"Edit privacy. Sharing with [setting]"ALWAYS use the STABLE PREFIX (never match dynamic suffix):
| Current Privacy | Full Accessible Name | ALWAYS Use This Selector |
|---|---|---|
| Public | "Edit privacy. Sharing with Public" | button="Edit privacy. Sharing with" |
| Friends | "Edit privacy. Sharing with Friends" | button="Edit privacy. Sharing with" |
| Only me | "Edit privacy. Sharing with Only me" | button="Edit privacy. Sharing with" |
| Friends except | "Edit privacy. Sharing with Friends except: John, Jane..." | button="Edit privacy. Sharing with" |
WRONG: ❌ button="Friends except..." (dynamic suffix, will fail)
WRONG: ❌ button="Public" (doesn't match full name)
CORRECT: ✅ button="Edit privacy. Sharing with" (stable prefix)
In privacy dialog (after clicking privacy button):
| Option | Selector |
|---|---|
| Public | radio=Public |
| Friends | radio=Friends |
| Only me | radio=Only me |
| Custom | radio=Custom |
# 1. Navigate to Facebook
browser_navigate(url="https://www.facebook.com")
browser_wait(time=2)
# 2. Get snapshot to find composer
browser_get_snapshot()
# Find button containing "What's on your mind"
# 3. Open composer
browser_click(selector='button=What\'s on your mind', force=True)
browser_wait(time=1)
# 4. Get snapshot - find privacy button (shows current setting)
browser_get_snapshot()
# Look for button starting with "Edit privacy. Sharing with" [ref=eXX]
# 5. Click privacy button using STABLE PREFIX selector
browser_click(selector='button="Edit privacy. Sharing with"', force=True)
browser_wait(time=0.5)
# 6. Select privacy option
browser_click(selector='radio=Only me', force=True)
browser_wait(time=0.5)
# 7. CRITICAL - Confirm with Done
browser_click(selector='button=Done', force=True)
browser_wait(time=0.5)
# 8. Type post content
browser_type(selector="role=textbox", text="Your post content")
browser_wait(time=1)
# 8b. CRITICAL - Refresh snapshot after typing (refs become stale)
browser_get_snapshot()
# 9. Click Next (if shown)
browser_click(selector='button=Next', force=True)
browser_wait(time=2)
# 10. Get snapshot, find Post button
browser_get_snapshot()
# 11. Click Post
browser_click(selector='button=Post', force=True)
browser_wait(time=3)
# 12. VERIFY - Must see post in feed
browser_get_snapshot()
browser_get_snapshot()
# Find Like button ref
browser_click(ref="e28", force=True) # Like button ref
browser_wait(time=0.5)
browser_get_snapshot() # Verify liked
browser_get_snapshot()
# Hover to reveal reactions
browser_hover(ref="e28") # Like button ref
browser_wait(time=1)
browser_get_snapshot()
# Click specific reaction
browser_click(ref="e35", force=True) # Love reaction ref
browser_get_snapshot()
browser_click(ref="e32", force=True) # Comment button
browser_wait(time=0.5)
browser_type(ref="e45", text="Great post!") # Comment input
browser_press_key(key="Enter")
browser_wait(time=1)
browser_get_snapshot() # Verify comment appears
| Problem | What Happened | Fix |
|---|---|---|
| Clicked wrong button | Used stale ref (e78 was "What's on your mind" but became "Live video") | ALWAYS browser_get_snapshot() after any action |
| Closed dialog accidentally | Clicked "Close composer dialog" instead of privacy button | Read button names in snapshot before clicking |
| Got stuck in loop | Clicking same ref repeatedly after page changed | Refs are per-snapshot; get fresh snapshot first |
| Privacy not changed | Selected option but didn't click "Done" | Complete full dialog: select → Done → verify |
| Problem | Solution |
|---|---|
| Ref not found | browser_get_snapshot() to refresh refs |
| Click not working | Add force=True, try browser_hover first |
| Element not visible | browser_wait(time=2), check for overlays |
| Dialog not responding | Close with browser_press_key(key="Escape") |
| Page stale | browser_navigate to refresh |
force=True