# Threads Auto Post

> Threads affiliate auto-post: v19 — Browserless HTTP primary + Shopee buyer-review 5★+media HD + Pinterest fallback + 1-post=1-link forever. Content CERITA/TIPS Viewbait v5: post_1 first line ALL CAPS + total ≥210 chars. Cron no_agent=true, script_timeout≥900, THREADS_ALLOW_UI_FALLBACK=0. See references/viewbait-v5-and-cron-timeout-fix.md. Triggers: post threads, review image, caption/hook, provid…

- **Type:** Skill
- **Install:** `agentstack add skill-sekolah76-syadagentic-threads-auto-post`
- **Verified:** Pending review
- **Seller:** [Sekolah76](https://agentstack.voostack.com/s/sekolah76)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Sekolah76](https://github.com/Sekolah76)
- **Source:** https://github.com/Sekolah76/syadagentic/tree/main/arsenal-skills/skills-lengkap/affiliate/threads-auto-post
- **Website:** https://github.com/Sekolah76/syadagentic

## Install

```sh
agentstack add skill-sekolah76-syadagentic-threads-auto-post
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Threads Affiliate Auto-Post (v18.0)

## CRITICAL RULES
- **Refs**: `references/shopee-review-image-and-dedup-v18.md` (product-only 5★+media HD scrape + permanent link dedup).
- **Pool/batch**: skill `affiliate-pool-isolation-and-batch` + `~/.hermes/scripts/affiliate_batch_manager.py` (auto-advance batch N→N+1 saat unused=0; pool 100 unique terverifikasi 2026-07-13).
- **Refs**: `references/affiliate-pool-batch-and-count.md` — auto-advance batch N→N+1 when UNUSED=0; isolated pools per channel; **always count unique `s.shopee.co.id` URLs** (header "100" can lie — was 97 until 3 missing links injected 2026-07-13).
- **1 Post = 1 Link Affiliate Forever**: Tidak boleh ada daur ulang (recycle) dari `USED` ke `UNUSED`. Permanent: `threads_used_links.json`. Simpan log di `~/.hermes/scripts/threads_used_links.json`.
- **Review Gambar Produk Real (Bukan Katalog)**: 
  - Wajib ambil ulasan pembeli bintang 5 dengan media (`5 bintang` + `dengan media`).
  - Tolak URL non-produk (halaman toko/shop homepage).
  - Ekstrak menggunakan `i.src` original (bukan `currentSrc` thumbnail `@resize_w144`).

## CRITICAL DISTINCTIONS
- **"Postingan"** = POST BARU (original content). Skill ini.
- **"Reply"** / **"Komentar"** = Balasan di postingan orang lain. Pakai `threads-auto-reply`.
- **JANGAN CAMPUR ADUK.**

## Shopee Review Image (MUST)
- **Product-link only.** Resolve affiliate shortlink → `/product/{shop_id}/{item_id}`. Reject shop/store URLs.
- **5★ + Dengan Media only.** Never product gallery / catalog / avatar.
- **HD original path:** use `img.getAttribute('src')` (or cleaned original). Do **not** prefer `currentSrc` — Shopee injects `@resize_w144_nl.webp` thumbs (~5KB).
- **Module:** `~/.hermes/scripts/shopee_scraper.py` → `scrape_review_image()`.
- **Cron wire:** `run_threads_post.sh` (`no_agent=true`) → `cron_post.py` → `get_real_review_photo()` **must** call `scrape_review_image` (do not re-inline old camoufox scraper).
- Full procedure + pitfalls: `references/shopee-review-scraper.md`
- **Shopee Review Image**: WAJIB link produk (bukan toko) + filter 5 Bintang + HD. Lihat `references/shopee-review-image-scraper.md`.

## Publish path (2026-07-13)
Engine order in `cron_post.py`:
1. **`threads_post_http.py`** — Browserless HTTP v2 (Image Upload + GraphQL/Rupload, 0 RAM, super-fast)
   - Image Upload: `POST /rupload_igphoto/fb_uploader_{upload_id}` (image/jpeg)
   - Configure Feed: `POST /api/v1/media/configure_text_post_app_feed/` (image root)
   - Chaining/Text replies: `POST /api/v1/media/configure_text_only_post/`
   - Speed: 0 RAM, ~1.2s per post, pure `urllib`/`requests`.
2. **`threads_post_applescript.py`** — Chrome Profile 16 live window  
   - Fill: **System Events paste** (`pbcopy` + cmd+v) — trusted input  
   - Send: score Kirim **y>300 x>700 first**, Quartz/OS mouse + Meta+Enter fallback  
   - Hook fetch/XHR for Create/Publish names  
   - Hard verify profile or mutation  
3. **`threads_post_p16_playwright.py`** — clone minimal P16 → `/tmp/chrome_threads_p16_ud`  
   - Non-default user-data so Chrome allows automation  
   - Playwright keyboard.type + mouse.click (trusted-ish)  
   - Clone Cookies/Network/Local Storage only; clear Singleton* locks  
4. **`threads_post_v6.py`** — legacy cookie inject (last resort)

Env override: `THREADS_FORCE_PLAYWRIGHT=1` → skip HTTP & AS, use cookie PW path only (debug).

## Browserless HTTP Engine Specification (configure_text_only_post)
- **URL**: `POST https://www.threads.net/api/v1/media/configure_text_only_post/`
- **Headers**:
  - `X-IG-App-ID`: `238260118697367` (Native Threads app ID)
  - `X-ASBD-ID`: `129477`
  - `Cookie`: MUST contain valid `sessionid`, `csrftoken`, `ds_user_id`
  - `X-CSRFToken`: value from `csrftoken` cookie
- **Payload Schema (urlencoded)**:
  - `publish_mode`: `text_post`
  - `timezone_offset`: `25200`
  - `caption`: post text content
  - `client_context`: `-`
  - `text_post_app_info`: JSON string containing:
    - Root post: `{"reply_control": 0}`
    - Child thread reply: `{"reply_control": 0, "reply_id": "", "is_reply": true, "reply_to_author": ""}`
  - `replied_to_media_id` (only for child replies): parent post `pk` (not code)
- **Success Criteria**: Response JSON status == `ok` AND `media.pk` (e.g. `3939965155132008399`) and `media.code` (e.g. `DatkW8LD2fP`) exist. Use `media.pk` as `replied_to_media_id` and `text_post_app_info.reply_id` for the next reply in the chain.

## Hard gate (same for all engines)

## Browserless / pure HTTP (research 2026-07-13)
Target: GraphQL `POST /api/graphql` tanpa browser. **Belum production.**
- IG cookie alone ≠ Threads session (pure HTTP SSO belum auto).
- Wajib: `lsd` + `fb_dtsg` + Threads session + mutation Create/Publish/Barcelona*Create*.
- Build order: hybrid network capture → `scripts/threads_post_http.py`.
- Full blueprint: `references/browserless-graphql-post.md`, `references/auth-preflight-jagonya.md`.

## 🔥 STORY MODE / JUAL CERITA

> **Publish hard-verify + anti-false-success:** `references/story-mode-publish-hard-verify.md`
> History canonical: `~/.hermes/scripts/threads_post_history.json` only (never skill-dir).
> **Kirim click ≠ success.** Write history / mark USED only after GraphQL Create/Publish mutation **or** strict profile `inner_text` unique snip (hook≥24 / product≥8 / link tail). See `references/kirim-publish-hard-verify.md`.
> **Send order:** bottom-right Kirim first (`y>300`, `x>700`, score≥100) → `has-text("Kirim").last force=True` → never prefer `has-text("Post").last` (false feed matches).
> **False soft-verify:** HTML-only / soft profile match without mutation caused false success 2026-07-12 — independent re-check; revert history if not live.
> Cookie: Chrome Profile 16 → `jagonya_shopee`; multi-domain inject IG + Threads.
> Pre-unpause: dry-run `threads_story_dry_run.py 12` + live post hard-verify; cron stays paused until SYADAGENTIC says unpause. (2026-07-12) — ACTIVE DEFAULT

**SYADAGENTIC redesign: posting = jual cerita, bukan review/value tip polos.**

Engine: `~/.hermes/scripts/threads_story_engine.py` · wired di `cron_post.py` v5.

### 3-beat formula (HARD)
| Post | Isi | Larangan |
|---|---|---|
| **1** | Scene + konflik (curhat) | ❌ produk, brand, CTA, link |
| **2** | Twist / insight cerita | ❌ hard CTA / link; product soft max ~40% |
| **3** | Resolusi + soft CTA + save + `s.shopee.co.id` | ✅ link HANYA di sini |

### 6 story types (rotasi, no repeat 4 last)
`keresahan_malam` · `malu_sosial` · `salah_beli` · `teman_bukti` · `open_loop` · `regret`

Mapped per kategori: skincare / parfum / haircare / makeup.

### Soft CTA bank
- "yang mau coba, link ada di bawah 🫶"
- "yang penasaran, gw taro link-nya 👇"
- "save dulu aja, nanti kalo butuh tinggal klik 📌"
- "buat yang mau coba, cek di bawah ya 🤍"

History fields: `hook_category` = story_type · `content_mode=story_v1` · `story_type`.

### Story ops (2026-07-12)
- **Dry-run:** `~/.hermes/scripts/threads_story_dry_run.py 12` (no browser) — must pass unique link/hook + no adjacent same story before unpause.
- **Dedup stack + USED mark:** `references/story-mode-dedup-no-agent.md`
- **Auth preflight (blocks live post):** `references/auth-preflight-jagonya.md` — verify session **is** `@jagonya_shopee` (`ds_user_id=3310347890`), not just `web_profile_info` 200. P16 can be logged in as another IG account (e.g. olivia.vanesso).
- History path **canonical only:** `~/.hermes/scripts/threads_post_history.json` (not skill dir).
- `cron_post.py` must use `if __name__ == "__main__"` guard (import-safe for dry-run).
- `mark_link_used` + DB sync **only after** publisher success.

## 🔥 SOFT SELLING RULE (2026-06-23) — still applies under story mode

**SYADAGENTIC explicitly wants SOFT SELLING.** Story mode is the implementation.

- **Thread 1–2: Pure story.** No hard product dump, no CTA.
- **Thread terakhir: Minimal CTA.** Soft line + link — NO "cek sekarang", NO "beli di sini".
- **Never brand-dump in hook.** Build curiosity first.
- **Tone: friend sharing, NOT seller.**
- Pattern: scene → twist → soft close + link

### Soft CTA examples (USE these):
- "yang mau coba, link ada di bawah 🫶"
- "yang penasaran, gw taro link-nya 👇"
- "save dulu aja, nanti kalo butuh tinggal klik 📌"
- "buat yang mau coba, cek di bawah ya 🤍"

### Hard CTA examples (DON'T use):
- ❌ "CEK SEKARANG SEBELUM KEHABISAN"
- ❌ "BELI DI SINI 👇👇👇"
- ❌ "Jangan sampai ketinggalan!"
- ❌ "FLASH SALE!!!"

## ⚠️ HARD RULE: WAJIB AFFILIATE LINK
- **POST TERAKHIR (3/5/6/7) HARUS contain `s.shopee.co.id/XXXX`** — no exceptions
- Jangan pernah posting thread tanpa link di post terakhir
- Kalau link database kosong → JANGAN POST, report to user instead
- User explicitly warned: "jangan postingan doang" — always verify POST TERAKHIR has link before Kirim
- **LINK INSERTION (v8)**: Use `navigator.clipboard.writeText()` + `Meta+v` paste. `keyboard.type()` does NOT trigger Threads' URL detection. Clipboard paste is the ONLY method that works (verified 2026-06-11).
- **PRE-SEND VERIFY**: check `editors.nth(N).inner_text()` contains link before clicking Send. If missing → retry with paste, then keyboard.type fallback.

## 📸 IMAGE STRATEGY — MANDATORY REAL USER REVIEW PHOTOS (v15 — 2026-06-27 CORRECTION)

**⚠️ CRITICAL 2026-06-27: Threads posts MUST use Shopee review images ONLY via Camoufox. NO Pinterest fallback. NO AI images. NO product thumbnails. NO random images. If Shopee returns no valid review image → SKIP IMAGE entirely.**

**⚠️ CRITICAL 2026-06-27 v2 — `/product/` URL FIX:** The resolved shortlink format `shopee.co.id/{shop_name}/{shop_id}/{item_id}` loads the STORE PAGE, not the product page. ALWAYS convert to `shopee.co.id/product/{shop_id}/{item_id}` format. Store pages have NO review images. This was SYADAGENTIC's frustration point: "Tolol tolol kenapa masuk ke toko nya sih anjing" and later "INI CONTOH LINK TOKO vs LINK PRODUK".

**⚠️ SCROLL LIMITATION (2026-06-27): JS-only extraction cannot reliably distinguish product carousel images from user review photos.** Shopee's rating-media-list uses randomized class names. Next build needs vision model or deterministic DOM traversal to section correct images.

SYADAGENTIC corrected this mid-session 2026-06-27: Pinterest search returned a valid-looking review image for the WRONG PRODUCT (Vienna Parfum Mist Rose Garden → wrong bottle). Mismatched photos are WORSE than no image. For Threads, image must match the affiliate product EXACTLY.

**2026-06-26: ALWAYS use REAL user review photos. NEVER generate AI images. NEVER use studio mockups.**

SYADAGENTIC explicitly prefers real photos from actual user reviews — people holding the product, swatches on skin, products on messy desks/nightstands. These convert better and look more trustworthy than studio shots.

### Acceptance Criteria for Images:
- ✅ Tangan memegang produk | Swatches di kulit | Produk ditaruh di meja/kasur kasual
- ✅ Pencahayaan natural (bukan studio) | Ada objek sekitar (boneka, gelas, kabel, dsb)
- ❌ AI-generated | Render 3D/mockup | Background putih polos terisolasi | Studio lighting sempurna

### Image Sourcing Priority (v15 — 2026-06-27, CORRECTED BY SYADAGENTIC):

**CRITICAL: Threads posts MUST use Shopee review images ONLY. Pinterest fallback caused mismatched product photos (SYADAGENTIC flagged this mid-session 2026-06-27 — Vienna Parfum Mist Rose Garden got wrong bottle image). For Threads, NO Pinterest, NO AI, NO random images. Only Shopee review via Camoufox — if invalid, skip image.**

#### Threads Posts (AFFILIATE):

1. 🥇 **Shopee Review Image via Camoufox** — PRIMARY
   Uses `camoufox` CLI attached to Chrome Profile 16 (`chrome_local_102130715962900495`) in headed mode:
   - **Product URL only:** resolve shortlink → `/product/{shop_id}/{item_id}`. Shop/store URL = hard REJECT. (`shopee_scraper.resolve_product_url`)
   - Opens product page via `camoufox browser open  "" --headed`
   - Scroll ~18× to mount rating overview (lazy). Do not stop on product-title "Penilaian" count alone.
   - Click filters in order: **`5 Bintang`** → **`Dengan Media`**
   - Extract ONLY buyer review imgs: `.rating-media-list img` / `img.rating-media-list__image-wrapper--image`
   - **HD trap:** use `i.getAttribute('src')` / `i.src` — NOT `currentSrc` (often `@resize_w144_nl.webp` ~5KB thumb)
   - Strip `@resize_w*_nl`, `.webp`, `_tn`, `_sm` → original `susercontent.com/file/{id}`
   - Validate: file size ≥20KB AND PIL resolution ≥250×250; pick highest `w*h`
   - Download to `/tmp/threads_post_image.jpg`
   - **Fallback:** if scraper fails OR images too small/invalid → empty string (skip image) — NEVER fallback to Pinterest for Threads
   - Implementation: `~/.hermes/scripts/shopee_scraper.py` + `get_real_review_photo()` in `cron_post.py`
   - **Key:** Chrome Profile 16 passes Shopee Akamai WAF with real browser fingerprint.
   ### ⚠️ Shortlink bug (fixed 2026-06-27 / reinforced 2026-07-13):
   Resolved URL `shopee.co.id/opaanlp/{shop_id}/{item_id}` can render as store-ish path. **ALWAYS convert to `/product/{shop_id}/{item_id}`.** Never open shop homepage. SYADAGENTIC: review image must come from product link, not store link.
   - **Reference:** `references/shopee-review-image-scraper.md` (2026-07-13 product-only + 5★ + HD)

2. **If no valid Shopee review image found → SKIP IMAGE entirely.** Do NOT use Pinterest, Bing, AI generation, or any other source. SYADAGENTIC explicitly corrected this 2026-06-27: mismatched review photos are worse than no image.

3. **DO NOT USE for Threads:** Pinterest search, Bing Images, AI generation, product thumbnails from Shopee gallery — all these sources can produce valid-looking images that DON'T match the affiliate product, which SYADAGENTIC called out as worse than no image.

### Bing Search ISP Limitation (Indonesia) — DEPRECATED (2026-06-26):

**Bing is no longer the primary image source.** Pinterest replaced it entirely.

- ISP Indonesia (Telkom/Telkomsel) melakukan DNS hijacking → SafeSearch Strict dipaksakan
- Beberapa kata kunci (seperti "Barenbliss", "lip tint") memicu false-positive filter pornografis
- `SRCHHPGUSR=ADLT=OFF` cookie tidak selalu berhasil
- **JANGAN andalkan Bing.** Gunakan Pinterest sebagai primary. Bing hanya last resort.

### Clipboard Paste Code Pattern (verified 2026-06-11):
```python
# MUST grant clipboard permissions on context
context.grant_permissions(["clipboard-read", "clipboard-write"])

def paste_text(page, text):
    """Paste text via clipboard — works better for URLs than keyboard.type()."""
    page.evaluate("""
        async (text) => {
            try {
                await navigator.clipboard.writeText(text);
            } catch(e) {
                // Fallback: create temp textarea
                const ta = document.createElement('textarea');
                ta.value = text;
                document.body.appendChild(ta);
                ta.select();
                document.execCommand('copy');
                document.body.removeChild(ta);
            }
        }
    """, text)
    time.sleep(0.3)
    page.keyboard.press("Meta+v")  # Cmd+V on Mac
    time.sleep(1)
```

### What DOES NOT work for URLs:
- ❌ `page.keyboard.type(url)` — Threads doesn't detect typed URLs
- ❌ `execCommand('insertText')` — same, no URL detection
- ❌ Synthetic `ClipboardEvent('paste')` — browser security blocks it
- ✅ `navigator.clipboard.writeText()` + `Meta+v` — WORKS

## ⚡ SHORT-FORM RULE (WAJIB IKUTI — 2026-06-05)

**Orang Indonesia MALAS BACA. Literasi rendah. Post pendek = menang.**

### Hard Rules:
- **MAX 1-2 kalimat per post** — lebih dari itu = user SKIP
- **⚠️ Script v8 = EXACTLY 3 posts (HARD PLATFORM LIMIT).** Content JSON with `post_1` through `post_3` only. Threads silently drops posts 4+ even though "Add to thread" reports success. **COMBO 6 KREATOR format must be compressed into 3 posts using ASBUN mapping.**
- **⚠️ Threads Domain Migration (2026-06-25):** Meta has permanently migrated Threads web app from `threads.net` to `threads.com` (redirects are active). In all Playwr

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Sekolah76](https://github.com/Sekolah76)
- **Source:** [Sekolah76/syadagentic](https://github.com/Sekolah76/syadagentic)
- **License:** MIT
- **Homepage:** https://github.com/Sekolah76/syadagentic

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** yes
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-sekolah76-syadagentic-threads-auto-post
- Seller: https://agentstack.voostack.com/s/sekolah76
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
