⚙️ Procesos activos
Dashboard
Resumen operativo en tiempo real
🔌 Servicios
🚨 Errores recientes
📋 Actividad reciente
📱 Granja IG
| Phone | Modelo | Cuenta IG | Estado | 📝 | 🔗 | Followers | Lang | Error | Acciones | |
|---|---|---|---|---|---|---|---|---|---|---|
| 📵 Sin IG 🔑 No log 🔌 Sin ADB 🖥️ Servidor caído — |
|
Selecciona phones para Multivista
✅ 🚫
·¿Eliminar este phone?
Esta acción es irreversible. Se eliminará:
Escanear phones
➕ Crear Phones
📸 Story Manager
Publicar IG Stories con link sticker via ADB
Publicar —
● ● Terminal Output
Cuentas
| Phone | IG | Estado | Info | |
|---|---|---|---|---|
📋 Resultados última publicación
📜 Historial de publicaciones
| Fecha | Modelo | Cuentas | OK | Failed | Link |
|---|---|---|---|---|---|
Content Library
root /
📅 Programación diaria por modelo
Siguiente story
Cola
Historial
📂 Stories Media
Media para stories — fotos y videos sin comprimir
📚 Docs
Documentación completa del proyecto Cupido Elite — Granja IG
Arquitectura del Sistema
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ MISSION CONTROL (localhost:9999) │
│ ┌─────────┐ ┌────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │Dashboard│ │ Phones │ │ Stories │ │Cookie Fix│ │Link Mgr │ │ Cerebro │ │Publisher │ │
│ │ KPIs │ │Grid/Ops│ │ Publish │ │ Cookies │ │ Bio Link │ │AI Brain │ │Reel/Post │ │
│ └─────────┘ └────────┘ └─────────┘ └──────────┘ └──────────┘ └─────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Account │ │ CAPTCHA │ │ Profile │ │
│ │ Creator │ │ Solver │ │ Editor │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ mc_server.py (Python http.server) │
│ Proxy: /proxy/geelark/* Skills: subprocess DB: data/mc.db │
└──────────┬──────────────────────┬───────────────────────┬───────────────────┬────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────────┐ ┌──────────────┐
│ GeeLark API │ │ FactoryM API │ │ Skills (subprocess) │ │External APIs │
│ openapi.gee… │ │ factorym.io │ │ ig-profile-checker │ │ SMSPool │
│ Bearer Token │ │ Bearer Token │ │ geelark-story-publisher│ │ 2captcha │
└────────┬────────┘ └──────────────────┘ │ ig-cookie-accepter │ └──────────────┘
│ │ ig-link-manager │
▼ │ ig-account-creator │
┌──────────────────────────────────────┐ │ ig-captcha-solver │
│ GeeLark Cloud Phones (~100) │ │ ig-profile-editor │
│ ┌──────┐ ┌───────┐ ┌──────┐ │ └─────────────────────────┘
│ │Luna │ │Natalia│ │Emma │ … │
│ └──┬───┘ └───┬───┘ └──┬───┘ │
│ └─────────┴────────┘ │
│ ADB over TCP (ip:port + glogin) │
└──────────────────┬──────────────────┘
│
▼
┌──────────────────┐
│ Instagram │
│ Stories / Bio │
│ Cookies / Scan │
│ Accounts/CAPTCHA│
└──────────────────┘
Flujo de datos
• Mission Control UI → fetch() → mc_server.py (localhost:9999)
• mc_server.py → proxy → GeeLark API (evita CORS del browser)
• mc_server.py → subprocess → skills/*/scripts/*.py (jobs en background thread)
• Skills → ADB TCP → Cloud phones → Instagram
• Account Creator / CAPTCHA Solver → SMSPool (números SMS) + 2captcha (resolución CAPTCHA)
• Configs (*_accounts.json) en data/accounts/, leídos/escritos por mc_server.py y los skills
• Registry global en data/phones_registry.json — estado de todos los phones
• Base de datos SQLite en data/mc.db — tablas: ig_accounts, publish_tasks
Estructura de archivos
MissionControlPhones/
├── mc_server.py ← Servidor principal (puerto 9999)
├── config.py ← Carga credenciales desde .env
├── start.sh ← Script de arranque
├── index.html ← Frontend (panel)
├── data/
│ ├── accounts/ ← *_accounts.json por modelo
│ ├── mc.db ← SQLite: ig_accounts, publish_tasks
│ ├── phones_registry.json
│ ├── story_configs.json
│ ├── publish_history.json
│ ├── phone_errors.json
│ └── agents_status.json
├── scripts/ ← Utilidades standalone
│ ├── scan_model.py
│ ├── map_all_accounts.py
│ ├── publish_story_api.py
│ └── update_status.py
├── skills/ ← Automatizaciones ADB
│ ├── ig-profile-checker/scripts/check_profile.py
│ ├── geelark-story-publisher/scripts/
│ │ ├── publish_story_v2.py (archivado)
│ │ └── publish_story_v4_human.py ← activo
│ ├── ig-cookie-accepter/scripts/accept_cookies_v2.py
│ ├── ig-link-manager/scripts/set_link_v2_threaded.py
│ ├── ig-account-creator/scripts/create_account.py
│ ├── ig-captcha-solver/scripts/solve_captcha.py
│ └── ig-profile-editor/scripts/edit_profile.py
└── content/ ← Imágenes/videos para stories
├── Luna/
├── Natalia/
└── ...
API Endpoints — mc_server.py
Todos los endpoints servidos en http://localhost:9999
Estado / Info
| Method | Path | Descripción | Response clave |
|---|---|---|---|
| GET | /api/status | Health check + uptime | {status, uptime, uptime_fmt} |
| GET | /api/phones/full | Lista phones con datos de scan del registry | {phones: [{id, name, ig, model, ...}]} |
| GET | /api/phones | Configs por modelo (de data/accounts/) | [{model, accounts, ...}] |
| GET | /api/configs | Resumen de todos los *_accounts.json | [{file, model, totalAccounts, verifiedAccounts, ...}] |
| GET | /api/config/:model | Config completo de un modelo | Contenido de data/accounts/<model>_accounts.json |
| GET | /api/scan/results | Resultados del último scan | {results: [...]} |
| GET | /api/publish/history | Historial de publicaciones | [{timestamp, model, total, success, failed, link}] |
Phones
| Method | Path | Descripción |
|---|---|---|
| POST | /api/phones/sync | Sincroniza lista de phones desde GeeLark API |
| POST | /api/phones/stopall | Para todos los phones encendidos (emergencia) |
| POST | /api/phones/delete | Elimina phone de GeeLark + FactoryM + config local |
Scan IG
| Method | Path | Descripción |
|---|---|---|
| POST | /api/phone/scan | Lanza scan de perfil IG individual — body: {phoneId} |
| POST | /api/phone/scan/status | Estado del scan individual — body: {jobId} |
| GET | /api/phone/scan/active | Lista scans individuales activos |
| POST | /api/phone/scan/bulk | Scan masivo de un modelo — body: {model, ...} |
| GET | /api/phone/scan/bulk/status | Estado del scan masivo — query: ?jobId=… |
| GET | /api/phone/scan/bulk/active | Lista scans masivos activos |
| POST | /api/phone/scan/bulk/cancel | Cancela scan masivo — body: {jobId} |
Acciones IG
| Method | Path | Descripción |
|---|---|---|
| POST | /api/publish/start | Lanza job de publicación de story |
| GET | /api/publish/status | Estado del job de publicación — query: ?jobId=… |
| POST | /api/cookies/accept | Lanza aceptación de cookies en phones |
| GET | /api/cookies/status | Estado del job de cookies |
| GET | /api/cookies/active | Lista cookie jobs activos |
| POST | /api/linkbio/start | Lanza set de link en bio |
| GET | /api/linkbio/status | Estado del job de link bio |
| GET | /api/linkbio/active | Lista link bio jobs activos |
Profile Editor
| Method | Path | Descripción |
|---|---|---|
| POST | /api/profile/start | Inicia job de edición de perfil — body: {model, field, value, target, phones, ...} |
| POST | /api/profile/status | Estado del job — body: {jobId} |
| POST | /api/profile/cancel | Cancela job de edición — body: {jobId} |
| GET | /api/profile/active | Lista profile jobs activos |
CAPTCHA Solver
| Method | Path | Descripción |
|---|---|---|
| POST | /api/captcha/start | Inicia resolución CAPTCHA — body: {phoneId, phoneName, twocaptchaKey?, smsKey?, country?} |
| POST | /api/captcha/status | Estado del job — body: {jobId} → {status, output, step, totalSteps, result?} |
| POST | /api/captcha/cancel | Cancela job y para el phone — body: {jobId} |
Account Creator
| Method | Path | Descripción |
|---|---|---|
| POST | /api/accounts/start | Inicia job de creación de cuenta — body: {phoneId, phoneName, fullName, username, password, smsMode, ...} |
| POST | /api/accounts/status | Estado del job — body: {jobId} → {status, output, step, waitingFor, result} |
| POST | /api/accounts/cancel | Cancela job — body: {jobId} |
| POST | /api/accounts/provide_input | Envía número o código SMS al script — body: {jobId, input} |
| POST | /api/accounts/resend_sms | Señaliza reenvío SMS — body: {jobId} |
| POST | /api/accounts/hero-balance | Consulta saldo SMSPool |
SMSPool
| Method | Path | Descripción |
|---|---|---|
| POST | /api/smspool/get_number | Pide número temporal a SMSPool desde el panel |
| POST | /api/smspool/poll_code | Comprobación única del código SMS (no bloqueante, 3s entre llamadas) |
| POST | /api/smspool/cancel | Cancela orden SMSPool activa |
Base de Datos
| Method | Path | Descripción |
|---|---|---|
| POST | /api/db/stats | KPIs: total cuentas, creadas, errores, hoy, tasa de éxito |
| POST | /api/db/accounts | Lista cuentas con filtros (search, status, offset, limit) |
| POST | /api/db/accounts/update | Edita campos de una cuenta por ID |
| POST | /api/db/accounts/delete | Elimina una cuenta por ID |
Contenido
| Method | Path | Descripción |
|---|---|---|
| GET | /api/content/list | Lista archivos en content/ con estructura por carpeta |
| POST | /api/content/upload | Sube archivo a content/ — multipart/form-data |
| POST | /api/content/mkdir | Crea carpeta en content/ — body: {path} |
| POST | /api/content/delete | Elimina archivo de content/ — body: {path} |
| PROXY | /proxy/geelark/* | Proxy POST a GeeLark API (evita CORS del browser) |
| GET | /sse | Server-Sent Events para integración MCP con Claude Code |
POST /api/publish/start — Parámetros
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| model | string | ✅ | Nombre del modelo (lee data/accounts/<model>_accounts.json) |
| media | string | ✅ | Ruta al archivo de imagen/video (ej: content/Luna/IMG_4506.PNG) |
| link | string | URL para link sticker | |
| stickerText | string | Texto del sticker (ej: "Free Today!!") | |
| target | string | verified|all|failed|selected (default: verified) | |
| phones | string | IDs separados por coma (para target=selected) | |
| skipLink | bool | Publicar sin link sticker | |
| dryRun | bool | Solo chequear conexiones sin publicar | |
| bootWait | int | Segundos espera tras boot (default 30) | |
| workers | int | Workers paralelos (default 3) | |
| screenshots | bool | Guardar screenshot post-publish | |
| keepRunning | bool | No parar phones después |
Story Publisher — Flujo Completo
Script: publish_story_api.py — Publica stories con link sticker via ADB en phones GeeLark
Lista phones via GeeLark API /phone/list, identifica cuáles necesitan arrancar
Arranca phones parados via /phone/start, espera boot-wait (default 30s)
/adb/setStatus → /adb/getData → adb connect ip:port → glogin pwd
adb push imagen → MEDIA_SCANNER_SCAN_FILE → am start ADD_TO_STORY intent
3 estrategias: S1 Coords guardadas → S2 content-desc="Stickers" → S3 Toolbar icons derecha
Tap Link → EditText → input text URL → segundo EditText para sticker text → Done
Tap "Your story"/"Tu historia" → screenshot (opcional) → rm media → stop phone (save credits)
Retry Logic
• max_retries=2 — si no encuentra LINK sticker, vuelve atrás y reintenta
• Cada retry: force-stop IG → relanzar story editor → espera 22s (más que intento inicial)
• Si todos los retries fallan → fallback: publica SIN link sticker
• Detección de restricción: si IG muestra "You need more followers" → marca como restricted y para
• Coords exitosas se guardan en config para acelerar próximas ejecuciones
Sticker Strategies (3 niveles)
| Estrategia | Cómo funciona | Cuándo se usa |
|---|---|---|
| S1 — Saved Coords | Usa stickerCoords + linkStickerCoords del config | Si hay coords de éxito previo |
| S2 — Content Desc | Busca content-desc="Stickers"/"Pegatinas" en UI XML | Fallback si S1 falla |
| S3 — Toolbar Icons | Prueba todos los NAF clickable icons en toolbar derecha | Último recurso, itera hasta 5 botones |
publish_story_v2.py
skills/geelark-story-publisher/scripts/publish_story_v2.py
Publica una story en Instagram con link sticker y texto personalizado. Soporta múltiples phones en paralelo. Usa agent-device para árbol de accesibilidad con fallback a uiautomator XML + coordenadas para phones 720x1440.
Uso
python3 publish_story_v2.py \ --phones <ids_separados_por_coma | group:NombreModelo> \ --media content/Natalia/12334.jpg \ --link clickmysocials.com/nataliapariish \ --link-text "Gratis Hoy!!" \ [--skip-link] [--dry-run]
Comportamiento por resolución
| Resolución | ADD_TO_STORY intent | agent-device | Método | Estado |
|---|---|---|---|---|
| 1080x2340 | Abre cámara sin imagen | ✅ Funciona | agent-device (árbol accesibilidad) | OK |
| 720x1440 | Abre editor con imagen | ❌ Árbol vacío | uiautomator XML + coordenadas | OK |
Toolbar derecho — coordenadas en phones 720x1440
⚠️ Comportamiento conocido
La posición del sticker varía según versión de IG
El código prueba y=8%→13%→18%→22% en loop
Detecta panel Aa por text_overlay / font_option en XML
NO usar nombres de fuente ("Modern","Classic") → falsos positivos
Fallbacks activos para 720x1440
| Paso | Fallback |
|---|---|
| Detectar editor abierto | uiautomator dump → busca "Your story / Add a caption / Tu historia" |
| Icono sticker | uiautomator content-desc "Add sticker" → loop coordenadas y=8%→13%→18%→22% hasta que no se detecte panel Aa |
| Link Sticker en tray | 1) tap directo text/desc "Link Sticker/Link/LINK" → 2) buscar "link" en search bar del tray (evita que teclado tape los stickers) → 3) scroll + último intento |
| Campo URL | Si url_node=None → tap EditText via uiautomator → input text ADB |
| Texto del sticker | input text ADB directo |
| Botón Done | uiautomator text="Done" → KEYCODE_BACK |
| Botón "Your story" | uiautomator text="Your story / Your Story / Tu historia" |
| Verificación post-publish | uiautomator busca story ring, feed, "Stories archive" popup |
| ⛔ Abortar si no hay link | Si se pidió link pero no se pudo añadir → force-stop IG → FAILED (nunca publica sin link) |
Conexión ADB — tiempos y reintentos
Boot wait
28s
tras /phone/start
ADB wait
8s
tras /adb/setStatus
getData reintentos
8×15s
≈1.75 min de margen
📦 Archivado — sustituido por v4
v2 se mantiene en scripts/archive/ como fallback. El servidor usa publish_story_v4_human.py para todos los modelos.
publish_story_v3_threaded.py
skills/geelark-story-publisher/scripts/publish_story_v3_threaded.py
Sustituido por v4. Disponible en scripts/archive/ como fallback. Versión con threading de v2 sin human behavior.
Uso
python3 publish_story_v3_threaded.py \ --phones <ids_separados_por_coma | group:NombreModelo> \ --media content/Lucia/foto.jpg \ --link https://myotherprofiles.com/luciii \ --link-text "Gratis Hoy!!🤗" \ [--skip-link] [--dry-run]
Fixes añadidos en v3 (2026-02-27)
| Fix | Descripción |
|---|---|
| Gallery early-return | Tras tap de galería, comprueba _has_editor() antes de intentar tap de foto. Si el editor ya está abierto, retorna inmediatamente. Evita que taps en banners/ImageView incorrectos rompan el estado del editor. |
| Sticker tray retry | Si el tray no se detecta tras el primer tap, reintenta en y=25%→28%→32%→35%→40%. Detecta y cierra panel Aa (text_overlay/font_option) en cada intento. |
| Sesión expirada | Si el editor nunca abre y el XML contiene Forgot password / log_in_button → FAILED: Instagram session expired. Phones con sesión expirada se eliminan via /api/phones/delete. |
| Text editor al inicio | Si IG arranca con panel de texto activo (text_overlay/font_option en XML), cierra con KEYCODE_BACK antes de navegar a galería. |
| Popup story-to-story | Modal "Introducing story-to-story sharing" bloquea el toolbar. Se detecta por Introducing / View settings en XML y se descarta tapeando "OK". |
| Emoji en sticker text |
adb input text no soporta emojis (chars 4-byte UTF-8). Cadena de fallback:1) fill_ref via agent-device (soporta Unicode completo)2) Si nodos vacíos → tap EditText via uiautomator + re-snap + fill_ref3) Si re-snap vacío (720x1440) → ADB sin emoji ( re.sub([^\x00-\x7F]))
|
Comportamiento por resolución (igual que v2)
| Resolución | ADD_TO_STORY intent | agent-device | Estado |
|---|---|---|---|
| 1080x2340 | Abre cámara → gallery tap (43,1144) → editor abierto | ✅ Funciona | OK |
| 720x1440 | Abre editor con imagen directamente | ❌ Árbol vacío | OK (uiautomator) |
publish_story_v4_human.py
skills/geelark-story-publisher/scripts/publish_story_v4_human.py
v3 + human behavior anti-detección: delays variables, jitter en taps, tipeo por chunks, nombre de archivo tipo cámara, micro-pausas. Activo para Luna. Mantiene threading.
Uso
python3 publish_story_v4_human.py \ --phones <ids_separados_por_coma | group:NombreModelo> \ --media content/Luna/foto.jpg \ --link clickmysocials.com/lunaa \ --link-text "Free Today!!" \ [--skip-link] [--dry-run]
Cambios anti-detección respecto a v3
| Helper | Comportamiento | Impacto |
|---|---|---|
| _sleep(base) | Cada espera = base × uniform(0.65, 1.35) — varía ±35% | 🔴 Alto |
| _tap(x, y) | Jitter ±5px en todas las coordenadas (dedo humano impreciso) | 🔴 Alto |
| _type(text) | Tipeo en chunks 2–5 chars con 80–200ms entre cada uno | 🔴 Alto |
| ui_tap() | Jitter ±4px inline en bounds calculados de uiautomator | 🟡 Medio |
| _pause() | Micro-pausa 0.4–1.4s antes de: sticker icon, link sticker, URL, texto del sticker | 🟡 Medio |
| Nombre media | IMG_YYYYMMDD_HHMMSS.JPG en DCIM/Camera/ (timestamp real de cámara) |
🟡 Medio |
| Swipe velocidad | Duración aleatoria randint(320, 550)ms en scroll del sticker tray | 🟢 Bajo |
✅ Resultado del primer run — Luna (2026-02-27)
6/6 stories publicadas. Threading paralelo: Luna7/8/11 publicando mientras Luna10/12/13 aún conectaban ADB. Luna8 encontró sticker via scroll tras 4 intentos fallidos en el toolbar — se resolvió automáticamente.
check_profile.py
skills/ig-profile-checker/scripts/check_profile.py
Escanea el perfil de Instagram de un phone: detecta username, followers, posts, link en bio, idioma, foto de perfil. Escribe resultados en data/accounts/*_accounts.json.
python3 check_profile.py --phone <phoneId> [--model NombreModelo]
accept_cookies_v2.py
skills/ig-cookie-accepter/scripts/accept_cookies_v2.py
Acepta automáticamente el popup de cookies de Instagram al abrir la app por primera vez o tras actualizaciones.
python3 accept_cookies_v2.py --phone <phoneId>
set_link_v2_threaded.py (activo)
skills/ig-link-manager/scripts/set_link_v2_threaded.py
Establece el link en bio de Instagram. Threading: cada phone corre en paralelo. Corrige bug crítico de v1 (cmd /c Windows-only que rompía agent-device en macOS).
python3 set_link_v2_threaded.py --phones <id1,id2,...> --link <url> --batch 3
| Cambio | v1 | v2 |
|---|---|---|
| agent-device | cmd /c (Windows-only → roto en macOS) | subprocess directo (macOS ✓) |
| Boot wait | 55s | 28s |
| ADB retry | 7 × 10s | 8 × 15s |
| Threading | Secuencial | ThreadPoolExecutor(max_workers=batch) |
| URL input | ADB input text | agent-device fill → ADB fallback |
| Columna Verified | Mostraba r.screenshot | Muestra r.verified (✅/⚠️/—) |
| Done button (save) | BACK si no se encuentra → descarta la URL | Coordinate tap escalada → guarda siempre |
| Resolución | Coordenadas hardcoded 720×1440 → falla en otras resoluciones | wm size + _scale() auto-escalado ✓ |
| XML node matching | <node[^/]/> solo self-closing → no encuentra "Add link" (nodo contenedor) | <node\s[^>]*> + filtro clickable="true" ✓ |
| URL EditText | Retornaba primer EditText en orden XML → podía ser campo Title (y=806) | Retorna EditText con menor y (topmost = campo URL) + sanity check 35% |
Navegación multi-resolución — coordenadas auto-escaladas
El script detecta adb shell wm size y escala todas las coordenadas con _scale(x, y, base=720×1440). agent-device devuelve árbol vacío en todas las resoluciones probadas.
| Paso | Método | 720×1440 | 1080×2400 | 1200×2652 |
|---|---|---|---|---|
| Profile tab | coord fallback | (648,1340) | (972,2233) | (1080,2467) |
| Edit profile | XML tap | ~(171,496) | ~(255,826) | ~(283,912) |
| Add link (Edit Profile) | XML tap → coord | ~(360,993) | ~(540,1507) | ~(600,1657) |
| + Add link (Links page) | coord fallback | (200,180) | (300,300) | (333,331) |
| URL EditText | XML find | ~(360,211) | ~(540,352) | ~(600,440) |
| Done button | XML → coord | (661,84) | (985,140) | (1083,157) |
<node\s[^>]*> + filtro clickable="true". También xml_find_edittext retornaba campo Title (y=806) en vez de URL (y=349) → sanity check cy > 35% screen height.
ADB proxy GeeLark — quirks descubiertos (2026-02-27)
1. exec-out y adb pull NO funcionan
El proxy ADB de GeeLark solo soporta adb shell. Para XML dump usar:
adb shell uiautomator dump /sdcard/ui_lm.xml adb shell cat /sdcard/ui_lm.xml
2. Proxy cierra conexiones idle tras ~2-3s
Después de esperar 12s al arranque de Instagram, ADB queda "device offline". Fix: llamar getData de nuevo, disconnect explícito, luego connect fresco + verify.
3. "already connected" pero "device offline" — estado TCP stale
adb disconnect + adb connect devuelve "already connected" pero sigue offline. Solución: gl_api("/adb/getData") → connect al port devuelto → verify loop 8×10s.
4. Initial connect — NO hacer disconnect previo
En la primera conexión, no desconectar antes. El proxy GeeLark necesita tiempo para estabilizar el túnel subyacente. Solo connect + sleep 3s + verify.
5. Resolución múltiple — detectar con wm size (fix 2026-02-27)
Phones con 1080×2400, 1080×2640, 1200×2652 fallaban con "Edit profile not found" porque las coordenadas hardcoded para 720×1440 apuntaban al lugar incorrecto.
_, out, _ = adb_cmd(f"-s {addr} shell wm size")
# → "Physical size: 1200x2652"
_res_w, _res_h = 1200, 2652
def _scale(x, y, base_w=720, base_h=1440):
return int(x * _res_w / base_w), int(y * _res_h / base_h)
px, py = _scale(648, 1340) # → (1080, 2467)
XML uiautomator — quirks descubiertos (2026-03-02)
6. "Add link" es un nodo contenedor no-self-closing
En Instagram, ciertos elementos de Edit Profile (como "Add link") son <node ...> con hijos, no <node .../>. El regex antiguo <node[^/]/> los ignoraba silenciosamente.
# Fix: regex + filtro clickable
for node_str in re.findall(r'<node\s[^>]*>', xml):
if 'clickable="true"' not in node_str:
continue # Evita thumbnails, pics, nodos no-interactivos
7. "Add External Link" — dos EditText: URL arriba, Title abajo
La página de añadir link externo tiene dos campos. El XML puede devolver el Title field (y≈800) antes que el URL field (y≈350). Siempre usar el EditText con menor y.
# Retornar EditText topmost (menor cy)
if best is None or cy < best[0]:
best = (cy, cx)
# Sanity check: si cy > 35% pantalla = Title field → blind tap
if cy > _res_h * 0.35:
coords = None # fallback a _scale(360, 150)
skills/ig-link-manager/scripts/archive/set_link_v1_sequential.pyTiempos ADB — Boot Wait
Probado con 14 phones Natalia (2026-02-26/27). Si ADB devuelve 42002 "phone is not running", no es un error permanente — el phone no ha terminado de arrancar.
| Evento | Espera mínima | Notas |
|---|---|---|
Tras /phone/start | 28 segundos | Boot completo del sistema |
Tras /adb/setStatus | 8 segundos | Antes de llamar /adb/getData |
| Si getData falla (42002) | reintentar ×8 cada 15s | Todos los phones conectan con tiempo correcto |
| Tras abrir Instagram (monkey) | Re-connect ADB | IG reinicia daemon ADB → la conexión cae. Llamar getData de nuevo, disconnect+connect+verify |
Regla: si ADB parece roto, primero esperar más — NO asumir phone dañado
Los 13/13 phones Natalia con ADB "offline" conectaron correctamente con los tiempos correctos.
create_account.py
skills/ig-account-creator/scripts/create_account.py
Crea cuentas de Instagram desde cero en phones GeeLark. Flujo de 20 pasos con verificación SMS vía SMSPool. Resultados guardados en data/mc.db.
Modos SMS
| Modo | Descripción | Timeout código |
|---|---|---|
| auto | SMSPool gestiona número y código internamente | 20 min |
| manual | Script pausa — el panel puede usar SMSPool directamente o introducir código a mano | 30 min |
Flujo panel-assisted (modo manual + SMSPool desde panel)
===WAITING_PHONE===)/api/smspool/get_number → obtiene número/api/accounts/provide_input → script continúa===WAITING_CODE===)/api/smspool/poll_code cada 3sTimeouts (actualizados 01/03/2026)
| Parámetro | Antes | Ahora | Motivo |
|---|---|---|---|
| Manual: esperar número/código | 10 min | 30 min | Instagram puede tardar mucho |
| Auto SMSPool: get_status | 5 min | 20 min | Misma razón |
| Panel: poll código SMS | 10s | 3s | Respuesta más rápida al usuario |
Persistencia entre pestañas
mc_acctJobId, mc_acctOutput y mc_acctStep en localStorage. Al volver a la pestaña Account Creator con un job activo, el polling y el log se recuperan automáticamente.
Base de Datos
| Endpoint | Descripción |
|---|---|
| /api/db/stats | KPIs: total, creadas, errores, hoy, tasa de éxito |
| /api/db/accounts | Lista con filtros (search, status, paginación) |
| /api/db/accounts/update | Editar campos de una cuenta por ID |
| /api/db/accounts/delete | Eliminar cuenta por ID |
| /api/smspool/get_number | Pide número a SMSPool desde el panel |
| /api/smspool/poll_code | Comprobación única del código (no bloqueante, 3s entre llamadas) |
| /api/smspool/cancel | Cancela orden SMSPool activa |
edit_profile.py
skills/ig-profile-editor/scripts/edit_profile.py
Edición masiva de bio, nombre y foto de perfil via ADB. Threading con batch size configurable. Soporta "Same for all" y "Per account".
Quirks conocidos
• Bio abre pantalla separada — tap Bio → nueva pantalla con Done
• Gboard autocorrect — Fix: ime set com.zixun.cph/.util.GeeInputMethodService
• Triple-tap + DEL para limpiar campo (no DEL spam en vacío)
• ad_fill NO soporta Unicode/emoji en GeeLark
solve_captcha.py
skills/ig-captcha-solver/scripts/solve_captcha.py
Resuelve "Confirm you're human" via 2captcha.com + verificación SMS con SMSPool post-CAPTCHA. 8 pasos, 3 reintentos CAPTCHA, timeout SMS 5 min.
Servicios requeridos
• 2captcha.com — TWOCAPTCHA_KEY en .env (~$2-3/1000 CAPTCHAs)
• SMSPool — SMSPOOL_KEY en .env (~$0.15/SMS, solo si IG pide verificación)
• Pillow — pip3 install Pillow (crop de imagen CAPTCHA)
Config Schema — *_accounts.json
Cada modelo tiene un archivo data/accounts/<model>_accounts.json
Campos raíz
| Campo | Tipo | Descripción |
|---|---|---|
| model | string | Nombre del modelo (Luna, Natalia, etc.) |
| defaultLink | string | URL por defecto para link sticker |
| defaultStickerText | string | Texto sticker (%s = espacio). Ej: "Free%sToday%s!!" |
| lastPublish | ISO date | Timestamp última publicación |
| totalAccounts | int | Total cuentas (auto-calculado) |
| verifiedAccounts | int | Cuentas verificadas (auto-calculado) |
| notes | string | Notas libres |
| accounts | array | Lista de cuentas (ver abajo) |
Campos por cuenta (accounts[])
| Campo | Tipo | Descripción |
|---|---|---|
| name | string | ID interno (Luna3, Luna9...) |
| phoneId | string | ID de phone GeeLark (18 dígitos) |
| ig | string | Handle IG (@luniitaa.mrt) |
| verified | bool | true si última publicación fue exitosa |
| lastResult | string | success | adb_offline | error |
| issue | string? | Descripción del último error |
| stickerStrategy | string | right_toolbar_button_2 | compose_view_button_2 | content_desc_stickers |
| stickerCoords | [x,y] | Coords del botón sticker (descubiertas automáticamente) |
| linkStickerCoords | [x,y] | Coords del sticker LINK en tray |
| screenRes | string | Resolución pantalla (720x1362) |
| igVersion | string | Versión IG detectada |
| igLanguage | string | Idioma UI detectado (en/es) |
| successCount | int | Publicaciones exitosas acumuladas |
| failCount | int | Fallos acumulados |
| restricted | bool | true si IG bloqueó link sticker |
| lastPublishTime | ISO date | Timestamp última publicación |
| lastScreenshot | string | Path al último screenshot |
| needsRestart | bool | Si el phone necesita restart antes de publicar |
Modelos y Cuentas
119 phones GeeLark, 43 cuentas IG mapeadas con @username real
| Modelo | Phones | Con IG | Sin IG | ADB Offline | Cuentas mapeadas |
|---|---|---|---|---|---|
| 🌙 Luna | 25 | 8 | 8 | 9 | @luunita.i23, @luuniitaaa.022, @luunita.x, @luunitaa12, @luuniita.04, @lunaxx.gmz, @lunitaa.gmz, @luunaax.22 |
| ✨ Emma | 5 | 4 | 0 | 1 | @emma_kattx, @emma_kattx2, @emma_kattx3, @emma_kattx5 |
| 🎀 Mimi | 12 | 8 | 0 | 4 | @mimiii_gtf2-6, @mimiii_gtf8-10 |
| 💃 Natalia | 22 | 5 | 4 | 13 | @natalyy.reel, @natalia.yummy, @natalii.parish + 2 pendientes |
| ❤️ Lucia/Luci | 38 | 17 | 10 | 11 | @lucii.lovelyy5, @lucix.lovelyx, @lucia.chik3, @luu.lovv4, @lu_lovelysx, +12 más |
| 🌸 Cindy | 6 | 1 | 2 | 3 | @cindyystrm |
| 📦 Otros | 11 | 0 | 1 | 10 | Reddit, Pruebas, Test, API-Created |
Datos del 19 Feb 2026. Los números en vivo están en la sección Granja IG (KPIs + auto-refresh 30s).
Luna — Detalle de cuentas
| Nombre | IG | Status | Sticker Strategy | Resolución | Issue |
|---|---|---|---|---|---|
| Luna2 | @luniitaa.mrt | offline | unknown | — | Server 199.190.44.226 ADB unresponsive |
| Luna3 | @luunita.i23 | verified | right_toolbar_button_2 | 720x1362 | — |
| Luna4 | @lunitax.pr | offline | unknown | — | ADB unresponsive |
| Luna5 | @lunnitaa.222 | offline | unknown | — | ADB unresponsive |
| Luna6 | @lunita.rdx | offline | unknown | — | ADB unresponsive |
| Luna7 | @luuniitaaa.022 | verified | right_toolbar_button_2 | 720x1362 | — |
| Luna8 | @luunita.x | verified | right_toolbar_button_2 | 720x1362 | — |
| Luna9 | @luunitaa12 | verified | compose_view_button_2 | — | — |
| Luna10 | @luuniita.94 | verified | compose_view_button_2 | — | — |
| Luna11 | @lunaxx.gmz | verified | right_toolbar_button_2 | 720x1362 | — |
| Luna12 | @lunitaa.gmz | verified | compose_view_button_2 | — | — |
| Luna13 | @luunaax.22 | verified | content_desc_stickers | — | — |
📡 Mapeo de Cuentas IG
Cómo se extrae el @username de Instagram de cada phone GeeLark
Flujo de mapeo (3 pasos)
Boot phone → /adb/setStatus open → /adb/getData → adb connect ip:port → glogin pwd
adb shell dumpsys account | grep www.instagram.com → extrae name=XXXXXXXXX (ID numérico de la cuenta IG)
Este comando lee las cuentas Android registradas. Si IG está instalado y logueado, aparece con su ID numérico.
adb shell curl -s "https://i.instagram.com/api/v1/users/{ID}/info/"
⚡ La petición se hace DESDE el phone, no desde el PC. Cada phone tiene su propia IP → sin rate limits de IG.
Devuelve: username, biography, external_url, follower_count, following_count, media_count, profile_pic
⚡ Por qué desde el phone (Phone-Proxy)
❌ Método viejo (desde PC): PC llama a la API de IG → tras ~30 peticiones IG bloquea la IP del PC por horas ("Please wait a few minutes")
✅ Método actual (Phone-Proxy): Cada phone ejecuta curl internamente → IG ve tráfico normal desde la IP del proxy del phone → sin límites
💡 Este método escala a cualquier número de phones. Se usa para mapeo, audits, y cualquier scraping futuro de IG.
Scripts
| Script | Función | Uso |
|---|---|---|
| scripts/map_all_accounts.py | Mapeo masivo de todos los modelos. Boot → ADB → dumpsys → curl desde phone → stop. Workers paralelos. Guarda en data/phones_registry.json. | python3 scripts/map_all_accounts.py --group all --workers 5 --skip-mapped --retry |
| skills/ig-profile-checker/scripts/check_profile.py | Scan de perfil IG via ADB. Abre IG en el phone, navega al perfil, extrae datos via uiautomator dump. | python3 scripts/scan_model.py --model Luna --batch 5 |
Estados posibles de un phone
| Estado | Indicador | Significado | Acción |
|---|---|---|---|
| success | @username visible | Mapeado correctamente con @ real | Listo para publicar |
| api_resolve_failed | ⏳ IG detectado — @ pendiente | Tiene ID numérico pero no se pudo resolver el @ | Ejecutar resolve_via_phone.py |
| no_ig_account | ❌ Sin IG instalado | Phone no tiene IG instalado o no está logueado | Instalar IG desde GeeLark panel |
| adb_data: code=42002 | ⚡ ADB offline | Servidor GeeLark no permite activar ADB | Contactar GeeLark o recrear phone en otro servidor |
| adb_offline | ⚡ ADB offline | ADB se activó pero el phone no responde | Reiniciar phone y reintentar |
| sin datos | Sin mapear | No se ha intentado mapear aún | Ejecutar map_all_accounts.py |
Datos del registry (phones_registry.json)
Archivo central que almacena el estado de todos los phones. Leído por server.py para mostrar en el panel.
| Campo | Tipo | Ejemplo | Descripción |
|---|---|---|---|
| ig | string | @luunita.i23 | Username de IG (@ real o @id:XXXXX si pendiente) |
| igNumericId | string | 80173762029 | ID numérico de la cuenta IG (de dumpsys) |
| hasBio | bool | false | ¿Tiene bio configurada? |
| bioText | string | "Link in bio 💕" | Texto de la bio (max 200 chars) |
| hasLink | bool | false | ¿Tiene enlace externo? |
| linkText | string | https://clickmy... | URL del enlace externo |
| followerCount | string | 142 | Número de seguidores |
| followingCount | string | 88 | Número de seguidos |
| postCount | string | 5 | Número de publicaciones |
| hasProfilePic | bool | true | ¿Tiene foto de perfil? |
| screenRes | string | 720x1440 | Resolución de pantalla del phone |
| lastResult | string | success | Resultado del último intento de mapeo |
| lastAudit | ISO date | 2026-02-18T22:46Z | Timestamp del último check |
| auditMethod | string | dumpsys+ig_api | Método usado para el mapeo |
📊 Estado actual del mapeo
Última actualización: 19 Feb 2026. Los KPIs en vivo están en la sección Granja IG.
🔍 Check Feed IG
Auditoría masiva de cuentas IG: verifica foto de perfil, bio, enlace, estado de login, y captura screenshots
Dos modos de operación
📡 Modo Map
• Extrae @username de cada phone
• Usa dumpsys account + IG API desde phone
• Rápido: ~35s por phone (boot + ADB + query)
• No abre Instagram en el phone
• Resultado: @username + stats básicos
🔍 Modo Audit
• Todo lo de Map + abre IG en el phone
• Navega al perfil y captura screenshot
• Verifica visualmente: foto, bio, link, feed
• Más lento: ~60s por phone
• Resultado: todo de Map + screenshots
API Endpoints del Check Feed
| Method | Path | Descripción |
|---|---|---|
| POST | /api/check/start | Lanzar job de mapeo/audit. Body: {mode, group, workers, bootWait} |
| POST | /api/check/status | Estado de un job. Body: {jobId} |
| POST | /api/check/jobs | Lista todos los jobs |
| POST | /api/screenshots | Lista screenshots del audit |
| GET | /screenshots/audit/* | Servir imágenes de screenshots |
Integración con Granja IG (Phones)
Flujo de datos: Check Feed → phones_registry.json → Panel Phones
Cuando un job de Check Feed termina, los resultados se escriben automáticamente en el registry. La sección Phones lee del mismo registry, así que los datos aparecen automáticamente (auto-refresh cada 30s).
Datos que pasan de Check Feed → Phone Card
Click en cualquier tarjeta de phone para ver el detalle completo incluyendo screenshots del audit.
🛡️ Reglas de seguridad
🔴 Auto-stop obligatorio: Todos los phones se apagan al terminar el job o en caso de error. Cada minuto encendido cuesta dinero.
🔴 Botón Stop All: Emergencia — apaga TODOS los phones con un click (POST /api/phones/stopall)
🟡 --keep-running: Opt-in. Solo si explícitamente se pide, los phones se quedan encendidos después.
🟢 Phone-proxy: Las peticiones a IG API se hacen desde dentro del phone via ADB curl. Sin rate limits.
Troubleshooting
⚡ ADB falla / code=42002 / "No ADB data" — LO MÁS COMÚN
→ Primera causa a revisar SIEMPRE: Boot Wait insuficiente
Síntoma: code=42002, "No ADB data after 5 attempts", o "adb_offline" en todos o varios phones
Causa más frecuente: El phone no ha terminado de arrancar cuando se llama a /adb/getData. El daemon ADB tarda en iniciarse.
Tiempos mínimos probados (14 phones Natalia, 26/02/2026):
- • Boot wait: 28s mínimo tras
/phone/start - • Tras
/adb/setStatus: 8s antes de llamar/adb/getData - • Si falla: reintentar
getDatahasta 5 veces con 12s entre intentos
✅ Los 14 phones de Natalia que parecían "ADB offline" conectaron perfectamente con el tiempo correcto.
Fix: Aumentar boot wait. Si tras 5 reintentos sigue fallando, entonces sí puede ser problema de servidor GeeLark → recrear phone.
🔴 ADB Offline / No credentials (problema real de servidor)
Síntoma: Falla incluso con boot wait largo y múltiples reintentos
Causa: Servidor GeeLark con ADB bloqueado o phone corrupto
Fix: Recrear phone en GeeLark panel (se asigna a otro servidor) o contactar soporte GeeLark.
🟡 No LINK Sticker Found
Síntoma: Script no encuentra sticker LINK tras 3 estrategias
Causa: UI de IG cambió, resolución diferente, o idioma no detectado
Fix: 1) Verificar manualmente que la cuenta tiene acceso a link sticker. 2) Borrar stickerCoords del config para forzar redescubrimiento. 3) Tomar screenshot para inspeccionar UI.
🔴 Link Sticker Restricted
Síntoma: "You need more followers" / restricted=true en config
Causa: IG requiere cierto número de seguidores para link sticker
Fix: Warmup la cuenta con más followers/engagement. Mientras tanto, usar --skip-link para publicar sin sticker.
🟡 UI Dump Failed
Síntoma: uiautomator dump devuelve vacío
Causa: IG aún cargando, phone lento, o ADB desconectado mid-session
Fix: Aumentar --boot-wait. Verificar conexión ADB. Reintentar (el script tiene retry automático).
🟡 IG Not in Foreground
Síntoma: "IG not in foreground" en output
Causa: Intent ADD_TO_STORY no abrió IG correctamente (popup, otra app encima)
Fix: Force-stop IG y reintentar. Verificar que no hay diálogos del sistema bloqueando.
🔵 Coords Hardcoded Fallan
Síntoma: Taps caen en lugar equivocado
Causa: Diferentes phones tienen diferentes resoluciones (720x1362 vs 1080x1920)
Fix: Borrar stickerCoords/linkStickerCoords del config para forzar auto-descubrimiento vía UI XML.
GeeLark API
Base: https://openapi.geelark.com/open/v1 — Todo POST con JSON body — Auth: Bearer token
| Endpoint | Descripción | Params clave |
|---|---|---|
| /phone/list | Lista phones con paginación | {page, pageSize} → data.items[] |
| /phone/start | Arrancar phones (max 100/call) | {ids: [...]} |
| /phone/stop | Parar phones | {ids: [...]} |
| /adb/setStatus | Habilitar/deshabilitar ADB | {ids: [...], open: true} |
| /adb/getData | Obtener IP:port:pwd para ADB | {ids: [...]} → data.items[{ip, port, pwd, code}] |
| /task/run | Ejecutar Task Flow en phone | {phoneId, flowId, params} |
| /phone/group/list | Lista grupos de phones | {} → data.items[] |
Rate Limits & Quirks
• 200 req/min, 24,000 req/hora
• Todos los endpoints son POST con JSON body (incluso los que "leen")
• El campo es ids (no phoneIds)
• ADB enable es /adb/setStatus (no /phone/adb/enable)
• Max 100 phones por llamada a start/stop/adb
• adb connect requiere glogin <pwd> después para autenticar
• Phones en servidor 199.190.44.226 tienen problemas recurrentes de ADB
• Task Flows nativos NO funcionan para stories con link sticker → por eso usamos ADB directo
Agentes del Sistema
Agentes especializados orquestados vía Claude Code (MCP en /sse)
Orquestador principal. Coordina todos los agentes, gestiona el panel Mission Control, toma decisiones estratégicas.
Community Manager. Monitoriza WhatsApp grupo "Cupido Elite Chats", gestiona comunicación.
GeeLark Manager. Controla la granja de phones, ejecuta Task Flows, sube contenido a las cuentas.
IG Checker. Audita cuentas via ADB: verifica foto perfil, enlace bio, estado de cada cuenta.
Content Researcher. Busca videos virales, descarga reels trending para reutilizar como stories.
RPA Builder. Crea automatizaciones ADB para GeeLark: scripts de publicación, edición de perfiles, warmup.
Bouncy Link Manager. Gestiona tracking links via Bouncy.ai API: short links, analytics de clicks, geo, devices.
📡 Phone Scanner — Scan de Perfiles IG
Sistema de escaneo masivo que extrae datos de perfil IG directamente desde la UI del phone via ADB
Flujo de scan (por phone)
GeeLark API /phone/start → espera status=1 (max 90s) → cada phone sale con su IP única via proxy ProxyEmpire
/adb/setStatus {open:true} → /adb/getData → adb connect ip:port → glogin pwd
adb shell wm size → ej: 1080x2400. Variaciones: 720x1440, 1080x2340-2712, 1200x2652, 1236x2750
Launch IG → tap profile tab (bottom-right, coords calculados según resolución) → espera 3s
uiautomator dump → parse XML → extraer username, followers, posts, bio, link, idioma IG
adb disconnect → /phone/stop → guardar resultado en JSON → siguiente phone
⚠️ Regla Crítica — 1 Phone = 1 IP
NUNCA escanear múltiples phones simultáneamente.
Cada phone GeeLark tiene su propio proxy ProxyEmpire con IP española o USA única. Al arrancar, IG ve tráfico desde esa IP.
Si arrancas 2+ phones del mismo servidor a la vez, podrían compartir IP → ban de IG por actividad sospechosa.
✅ Flujo correcto: boot 1 → scan → stop → boot siguiente → scan → stop → ...
Username Detection — Patrones regex
El scan usa múltiples regex sobre el UI XML dump para encontrar el @username:
| Prioridad | Patrón | Descripción |
|---|---|---|
| 1 | action_bar_title text="..." | Título del action bar (IG clásico) |
| 2 | action_bar_textview_title | Variante del action bar |
| 3 | title_text text="..." | IG versiones nuevas |
| 4 | Fallback: lowercase text matches | Busca textos cortos a-z que parezcan usernames, filtrando palabras comunes |
⚠️ Algunos phones devuelven "???" — IG versiones muy nuevas cambian el layout del XML. Requiere actualizar patrones.
Datos extraídos
| Campo | Fuente | Ejemplo |
|---|---|---|
| username | UI XML regex | @lucii_loveex |
| followers | content-desc="N followers" | 142 |
| posts | content-desc="N posts" | 5 |
| bio | profile_header_bio_text | "Link in bio 💕" |
| link | profile_header_website | clickmy.bio/xxx |
| screenRes | adb shell wm size | 1080x2400 |
| igLanguage | UI keywords (Posts/Publicaciones) | en / es |
| status | Detection logic | ok / not_logged_in / no_ig / error |
Scripts
| Script | Función | Uso |
|---|---|---|
| skills/ig-profile-checker/scripts/check_profile.py | Scan individual o masivo via ADB. Llamado por mc_server.py para los endpoints /api/phone/scan y /api/phone/scan/bulk. |
python3 scripts/scan_model.py --model Luna |
| scripts/scan_model.py | Wrapper standalone. Lee error registry, calcula boot-wait y batch size óptimos, lanza check_profile.py, guarda log. | python3 scripts/scan_model.py --model Natalia --batch 5 --retry |
Resultados en el panel
Los resultados se guardan en data/accounts/<model>_accounts.json y se integran en la respuesta de /api/phones/full.
Cada phone card en la sección Phones muestra: @username, idioma IG (badge en/es), resolución de pantalla, y estado del scan.
El botón 🔍 en cada card lanza un scan individual (/api/phone/scan). Los botones por modelo lanzan scans en bulk (/api/phone/scan/bulk).
El registry global data/phones_registry.json almacena el historial de todos los phones y es leído por /api/phones/full.
Publisher — Reels & Posts via GeeLark RPA
Sin ADB · Sin boot wait · Scheduling nativo · SQLite local
Endpoints del panel
| Método | Path | Descripción |
|---|---|---|
| POST | /api/publish/reel | Publica reel en N phones. Body: {phones, phoneNames, igUsernames, model, media, caption, scheduleAt, intervalMinutes} |
| POST | /api/publish/post | Publica post (imagen) en N phones. Mismos campos que /reel |
| GET | /api/publish/tasks | Lista tareas. Params: ?date=today|week, ?type=reel|post|all, ?status=all|pending|done|failed |
Flujo por publicación
1. Upload media → upload_to_geelark(path) → CDN URL (caché por path+mtime → 1 upload para N phones)
2. Para cada phone: calcular scheduleAt = base + (idx × intervalMinutes × 60) × 1000ms
3. POST GeeLark RPA → /rpa/task/instagramPubReels o instagramPubReelsImages
4. Guardar en SQLite tabla publish_tasks con task ID, status y respuesta completa
5. GeeLark enciende el phone automáticamente en scheduleAt y ejecuta la tarea RPA
⚠️ Pendiente verificar (02/03/2026)
• Formato exacto de respuesta de /file/upload (se asume data.url)
• Nombres exactos de endpoints RPA (instagramPubReels / instagramPubReelsImages)
• Campos adicionales que pueda requerir la API RPA de GeeLark
Tabla publish_tasks (SQLite data/mc.db)
| Campo | Tipo | Descripción |
|---|---|---|
| job_id | TEXT | Task ID devuelto por GeeLark RPA |
| type | TEXT | reel | post |
| method | TEXT | rpa (siempre) |
| media | TEXT | URL en CDN de GeeLark (no ruta local) |
| schedule_at | INTEGER | Unix timestamp en segundos (NULL = inmediato) |
| status | TEXT | scheduled | running | done | failed |
| result_detail | TEXT | JSON completo de respuesta GeeLark |
Account Creator — Creación de cuentas IG
skills/ig-account-creator/scripts/create_account.py
Crea cuentas de Instagram desde cero en phones GeeLark. Flujo de 20 pasos: boot ADB → SMSPool número → abrir IG → rellenar formulario → verificar SMS → configurar perfil. Resultados guardados en data/mc.db (tabla ig_accounts).
Argumentos del script
| Argumento | Descripción |
|---|---|
| --phone-id | ID GeeLark del phone |
| --phone-name | Nombre del phone |
| --full-name | Nombre completo de la cuenta |
| --username | Username tentativo (el script prueba variantes si está tomado) |
| --password | Contraseña |
| --sms-key | API key de SMSPool |
| --country | Código de país para SMSPool (default: "es") |
| --sms-mode | "auto" | "manual" (default: "auto") |
| --job-id | ID del job (comunicación IPC con mc_server.py) |
Modos SMS
| Modo | Descripción | Timeout |
|---|---|---|
| auto | SMSPool gestiona número y código internamente | 20 min |
| manual | Script pausa — el panel puede usar SMSPool directamente o introducir código a mano | 30 min |
| panel-assisted | UI: "Pedir a SMSPool" + auto-poll código. Internamente es modo manual, pero el panel llama a SMSPool | 30 min |
Comunicación IPC (modo manual)
El script usa archivos /tmp/ como canal IPC con mc_server.py:
| Archivo | Dirección | Propósito |
|---|---|---|
| /tmp/acct_{job_id}_phone.txt | panel → script | Número de teléfono a registrar |
| /tmp/acct_{job_id}_code.txt | panel → script | Código SMS de 6 dígitos |
| /tmp/acct_{job_id}_resend.txt | panel → script | Señal de reenvío SMS |
Marcadores stdout (IPC)
===WAITING_PHONE=== → job['waitingFor'] = 'phone'===WAITING_CODE=== → job['waitingFor'] = 'code'===STEP===N===TOTAL → job['step'] = N===JSON_OUTPUT=== → Resultado final (JSON)Flujo panel-assisted
===WAITING_PHONE===)/api/smspool/get_number → obtiene número/api/accounts/provide_input → script continúa===WAITING_CODE===)/api/smspool/poll_code cada 3sTimeouts (actualizados 01/03/2026)
| Parámetro | Antes | Ahora | Motivo |
|---|---|---|---|
| Manual: esperar número/código | 10 min | 30 min | IG puede tardar mucho |
| Auto SMSPool: get_status | 5 min | 20 min | Misma razón |
| Panel: poll código SMS | 10s | 3s | Respuesta más rápida |
Base de Datos — tabla ig_accounts
| Campo | Tipo | Descripción |
|---|---|---|
| id | INTEGER PK | Autoincrement |
| created_at | TEXT | Timestamp ISO |
| job_id | TEXT | ID del job que creó la cuenta |
| phone_id | TEXT | ID del phone GeeLark |
| phone_name | TEXT | Nombre del phone |
| full_name | TEXT | Nombre completo |
| username | TEXT | Username tentativo |
| ig_username | TEXT | Username final asignado por IG |
| password | TEXT | Contraseña |
| birthdate | TEXT | Fecha de nacimiento (YYYY-MM-DD) |
| phone_number | TEXT | Email iCloud o número SMS usado |
| activation_id | TEXT | Order ID de SMSPool (o "manual") |
| country | TEXT | País del número SMS |
| status | TEXT | created / sms_timeout / username_taken / error |
| step_failed | TEXT | Nombre del paso donde falló |
Endpoints del panel
| Endpoint | Descripción |
|---|---|
| POST /api/accounts/start | Inicia job de creación |
| POST /api/accounts/status | Estado del job (output, step, waitingFor, result) |
| POST /api/accounts/cancel | Cancela job |
| POST /api/accounts/provide_input | Envía número o código al script vía /tmp/ |
| POST /api/accounts/resend_sms | Señaliza reenvío SMS |
| POST /api/accounts/hero-balance | Consulta saldo SMSPool |
| POST /api/smspool/get_number | Pide número a SMSPool |
| POST /api/smspool/poll_code | Poll único del código SMS (3s entre llamadas) |
| POST /api/smspool/cancel | Cancela orden SMSPool activa |
Persistencia (localStorage)
mc_acctJobId, mc_acctOutput y mc_acctStep en localStorage. Al volver a la pestaña Account Creator con un job activo, el polling y el log se recuperan automáticamente.
CAPTCHA Solver — Resolución automática de CAPTCHAs
skills/ig-captcha-solver/scripts/solve_captcha.py
Resuelve automáticamente el challenge "Confirm you're human" de Instagram (CAPTCHA de texto distorsionado) usando 2captcha.com. Si después del CAPTCHA aparece verificación de número móvil, la gestiona automáticamente con SMSPool.
Argumentos del script
| Argumento | Descripción |
|---|---|
| --phone-id | ID GeeLark del phone |
| --phone-name | Nombre del phone |
| --twocaptcha-key | API key de 2captcha.com |
| --sms-key | API key de SMSPool (para verificación móvil post-CAPTCHA) |
| --country | Código de país para SMSPool (default: "es") |
Requisitos
| Servicio | Variable .env | Coste | Para qué |
|---|---|---|---|
| 2captcha.com | TWOCAPTCHA_KEY | ~$2-3/1000 | Resolver imagen CAPTCHA |
| SMSPool | SMSPOOL_KEY | ~$0.15/SMS | Verificación móvil post-CAPTCHA |
| Pillow | pip3 install Pillow | Gratis | Crop de imagen CAPTCHA |
Flujo (8 pasos)
10 reintentos × 12s. Boot wait + adb connect + glogin
Intent directo a la app
Busca "Confirm you're human" en UI dump. Si no hay CAPTCHA → detecta phone verification o sale
Hasta 3 intentos con "Get a new code" entre cada uno. Crop del ImageView mejora precisión
Si no pide → proceso completado
País: España (ES +34). Pools fallback: 3 → 12 → 7 → auto
Max 5 min. Cancel + refund si timeout
Multi-button search: Next / Confirm / Continue
Detección de pantallas
| Pantalla | Texto detectado en XML | Función |
|---|---|---|
| CAPTCHA | "Confirm you're human" | detect_captcha() |
| Phone verification | "Enter your mobile number" | detect_phone_verification() |
| SMS code input | "Enter the code", "confirmation code" | detect_sms_code_screen() |
Crop de imagen CAPTCHA
El script localiza el ImageView del CAPTCHA en el XML (típicamente bounds [146,546][934,743] en 1080x2340) y recorta solo esa área para enviar a 2captcha.
• Bounds: width > 200px, height > 80px, y > 200 (descarta iconos)
• Crop con Pillow + 10px padding
• Fallback: si Pillow no está instalado, envía screenshot completo
2captcha API
| Paso | Endpoint | Params clave |
|---|---|---|
| Submit | POST 2captcha.com/in.php | method=base64, body=<img>, numeric=1, min_len=4, max_len=8 |
| Poll | GET 2captcha.com/res.php | action=get, id=<captcha_id> |
• Polling cada 5s, timeout 120s
• Tasa de éxito esperada: ~95-99% (CAPTCHAs de texto numérico distorsionado)
• Si falla, el script pide "Get a new code" y reintenta (hasta 3 veces)
Verificación de móvil post-CAPTCHA
Instagram puede pedir verificación de número después del CAPTCHA. El script usa un número nuevo temporal de SMSPool — no necesita ser el mismo con el que se creó la cuenta.
• País por defecto: España (ES +34)
• SMSPool cancela y devuelve el crédito si el SMS no llega en 5 min
Endpoints del panel
| Endpoint | Descripción |
|---|---|
| POST /api/captcha/start | Inicia job. Body: {phoneId, phoneName, twocaptchaKey?, smsKey?, country?} |
| POST /api/captcha/status | Estado: {status, output, step, totalSteps, result?} |
| POST /api/captcha/cancel | Cancela job y para el phone |
Resultados posibles
| result.status | Significado |
|---|---|
| solved | CAPTCHA resuelto + teléfono verificado |
| captcha_only | CAPTCHA resuelto, no pidió verificación de móvil |
| no_captcha | No se detectó CAPTCHA al abrir Instagram |
| partial | Algún paso completó pero el estado final no es claro |
| error | Fallo con stepFailed indicando el paso exacto |
Profile Editor — Edición bulk de perfiles IG
skills/ig-profile-editor/scripts/edit_profile.py
Edición masiva de bio, nombre y foto de perfil via ADB en phones GeeLark. Soporta modo "Same for all" (mismo valor para todos) y "Per account" (valor distinto por cuenta). Threading con batch size configurable.
Campos editables
| Campo | Método ADB | Notas |
|---|---|---|
| Bio | Tap Bio EditText → pantalla separada → triple-tap select all → DEL → type texto → tap Done | Bio abre pantalla separada en IG |
| Nombre | Tap Name EditText → triple-tap select all → DEL → type texto → back | ad_fill NO soporta Unicode/emoji |
| Foto de perfil | adb push → media scanner → tap "Edit picture" → "Choose from library" → gallery selecciona la más reciente | Funciona con JPG/PNG |
Flujo por phone (13 pasos)
Boot wait 28s + ADB retry 8×15s
Cambiar a GeeInputMethodService (sin autocorrect de Gboard)
Intent + tap profile tab
Busca "Edit profile"/"Editar perfil" en XML
Bio: pantalla separada con Done. Name: inline. Photo: push + gallery
Tap checkmark/Done → verificar cambios → stop phone
Quirks importantes
Bio abre pantalla separada
Al tocar el campo Bio en Edit Profile, Instagram abre una pantalla nueva con botón Done/checkmark arriba. No es inline como Name.
Gboard autocorrect
settings put secure spell_checker_enabled 0 NO funciona. Fix real: ime set com.zixun.cph/.util.GeeInputMethodService (IME de GeeLark sin autocorrect)
Limpiar campo: Triple-tap + DEL
NO hacer DEL spam excesivo (160 DELs) en campo vacío — Android interpreta backspace en vacío como "back" → sale de la pantalla
ad_fill NO soporta Unicode/emoji
En GeeLark: "Non-ASCII text input is not supported". Usar solo texto ASCII para nombres.
Modos de valor
| Modo | Descripción |
|---|---|
| Same for all | El mismo valor se aplica a todos los phones seleccionados |
| Per account | Se especifica un valor distinto para cada phone/cuenta |
Endpoints del panel
| Endpoint | Descripción |
|---|---|
| POST /api/profile/start | Inicia job de edición. Body: {model, field, value, target, phones, ...} |
| POST /api/profile/status | Estado del job — {jobId} |
| POST /api/profile/cancel | Cancela job de edición |
| GET /api/profile/active | Lista profile jobs activos |
Threading
Usa ThreadPoolExecutor con batch size configurable (default 3). Cada phone se procesa en su propio thread con boot + ADB independiente. El job dict _profile_jobs en mc_server.py trackea progreso de cada phone individual.
🍪 Cookie Accepter
Accept cookie consent popups on Instagram for active phones.
Select Phones
Settings
Progress
Log
Results
| Phone | Name | Result | Details |
|---|---|---|---|
Profile & Links
Manage Instagram bios, names, photos, and website links in bulk via ADB.
All Active Phones
Settings
Progress
Log
Results
| Phone | Name | Result | Link | Verified |
|---|---|---|---|---|
| ✅ ⚠️ — |
Apply to all selected
Edit per account
| ✓ | Phone | Name | Bio |
|---|---|---|---|
Progress
Output
Results
| Phone | Name | Bio | Photo | Status |
|---|---|---|---|---|
| ✓ ✗ — | ✓ ✗ — | ✓ ✗ — |
👤 Account Creator
Crea cuentas de Instagram en phones GeeLark usando verificación SMS Pool o Email
📱 Phone
👤 Datos de cuenta
🔐 Método de verificación
El script pausará cuando IG envíe el código — introdúcelo manualmente desde el panel.
El script pausará en paso 2 y paso 13 — tú introduces el número y el código SMS desde el panel.
📊 Progreso
📋 Log
LIVE📱 Número de teléfono
📨 Código SMS
📧 Código de verificación Email
🏆 Resultado
📋 Historial de cuentas creadas
Guardado permanentemente en data/created_accounts.json
| Fecha | Phone | Nombre | @Username IG | Contraseña | Cumpleaños | Email / SMS | Estado | Info |
|---|---|---|---|---|---|---|---|---|
| •••••••• |
| # | Fecha | Phone | Nombre completo | @Username IG | Contraseña | Cumpleaños | Email / SMS | País | Estado | Error en | Acciones |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Cargando... | |||||||||||
| Sin registros | |||||||||||
| — | •••••• |
|
|||||||||
✏️ Editar Cuenta
CAPTCHA Solver 🚧
Resuelve CAPTCHAs "Confirm you're human" via 2captcha + verificacion SMS via SMSPool
En desarrollo — Requiere API key de 2captcha.com (TWOCAPTCHA_KEY en .env). La verificacion SMS usa SMSPool (misma key que Account Creator).
Phone
Configuracion
Como funciona: 1) Arranca el phone y abre Instagram → 2) Detecta el CAPTCHA "Confirm you're human" → 3) Envia la imagen a 2captcha para resolver → 4) Introduce el codigo y pulsa Next → 5) Si aparece verificacion de movil, usa SMSPool automaticamente
Progreso
Log
Resultado
📤 Manual Publisher
Publica Reels y Posts via GeeLark RPA — sin ADB, sin boot wait
| Hora | Phone / @IG | Tipo | Caption | Programado | Estado |
|---|---|---|---|---|---|
|
Task ID (GeeLark)
Modelo
Media
Caption completo
Respuesta API GeeLark
|
|||||
📋 Mis Tareas
Vista unificada de todas las publicaciones — Stories, Reels y Posts
🤖 AutoPublisher
Supabase + VPS — publicaciones automatizadas
Pendientes de Caption
| Modelo | Cuenta | Archivo | Caption | Acciones |
|---|---|---|---|---|
Próximas Publicaciones
| Modelo | Cuenta | Archivo | Programado | Countdown | Estado |
|---|---|---|---|---|---|
|
|
Cuentas por Modelo
| Modelo | Cuentas | Usernames | Estado |
|---|---|---|---|
|
|
|
Activo |
Historial de Publicaciones
| Modelo | Cuenta | Archivo | Fecha | Estado | Error |
|---|---|---|---|---|---|
|
|
Contenido por Modelo
🔄 Repurpose
Genera variantes con hashes unicos via FFmpeg
Modificaciones que aplica FFmpeg
brew install ffmpeg📈 Analytics
Estadísticas de cuentas de Instagram
Crecimiento de Followers
| Cuenta | Modelo | Followers | Views | Likes | Comments | Saves | Posts | Engage% | Karma |
|---|---|---|---|---|---|---|---|---|---|
Requiere GL_APP_ID y GL_API_KEY en .env
Twitter Automation
⚙️ Configuración
🕐 Horarios (Madrid)
Distribución de estilos