# Sincronizar instancias de BlueStacks y LDPlayer en MAS

> Sincronizar instancias de BlueStacks o LDPlayer en MAS: añade cada instancia por puerto, agrúpalas y da a cada dispositivo su perfil y su proxy.

Source: https://automationmacro.com/es/docs/guides/multi-instance (Guías, updated 2026-09-05)

Una macro, cinco cuentas, un clic: eso es sincronizar instancias de BlueStacks o LDPlayer para farmear con un emulador Android multi instancia. Macro Automation Studio (MAS) trata cada instancia del emulador como un dispositivo aparte, y sincronizar instancias de BlueStacks o LDPlayer consiste en meterlas en un grupo de dispositivos que ejecuta la misma macro en todas, con argumentos por dispositivo, un proxy para cada una y un almacenamiento que nunca mezcla contadores. Esta guía monta esa configuración en BlueStacks, LDPlayer, MuMu Player o MEmu. Está pensada para quien lleva más de una cuenta.

## Antes de empezar

- MAS está instalado y con sesión iniciada con un plan cuyo número de dispositivos cubre las instancias que quieres ejecutar a la vez. Consulta [Facturación](/docs/billing).
- El gestor de instancias múltiples del emulador ha creado las instancias y cada una tiene ADB activado. Las guías de [BlueStacks](/docs/bluestacks-setup-guide), [LDPlayer](/docs/ldplayer-setup-guide), [MuMu Player](/docs/mumu-setup-guide) y [MEmu](/docs/memu-setup-guide) muestran dónde están el ajuste y el puerto.
- Todas las instancias usan la misma resolución y el mismo DPI que la instancia donde capturaste las plantillas.
- La macro funciona en una instancia desde el Code Editor. Consulta la [guía de bucles](/docs/guides/loops-and-scheduling).

## Cada instancia de un emulador Android multi instancia es un dispositivo

Una instancia de emulador escucha adb en su propio puerto TCP local. MAS encuentra las instancias recorriendo los procesos en ejecución y conservando los puertos dentro del rango conocido de cada emulador. Dos ventanas de BlueStacks aparecen así como dos entradas en la lista **Puerto**. El dispositivo es el puerto; el grupo es la lista de puertos.

| Emulador | Puertos que acepta MAS |
|---|---|
| BlueStacks | De 5555 a 8500 |
| LDPlayer | Puertos impares de 5555 a 5599 |
| MuMu Player | Puertos impares de 5555 a 5599, 7555, de 16384 a 16576, de 26624 a 27264 |
| MEmu | 21503 y todos los puertos terminados en 3 por encima, hasta 30000 |

Mantén todas las instancias abiertas mientras las añades; una instancia detenida no tiene puerto que encontrar. La página [Dispositivos](/docs/devices) tiene las reglas de detección completas.

## Crear un grupo de dispositivos

1. Abre **Grupos de dispositivos** y haz clic en **Crear nuevo grupo**.
2. Escribe un **Nombre**, deja el tipo **Local** y haz clic en **Crear grupo**.
3. Abre el grupo y haz clic en **Añadir dispositivo**.
4. Escribe un **Nombre del dispositivo** que diga de qué cuenta es, por ejemplo `farm-alt-2`.
5. Elige el puerto de la instancia en **Puerto**. Haz clic en **Actualizar** si falta, o elige **Puerto personalizado** y escríbelo.
6. Haz clic en **Añadir dispositivo** y repite con cada instancia.
7. En cada tarjeta de dispositivo, elige la macro en el selector **Macro**.

Un puerto solo puede pertenecer a un dispositivo. Añadirlo dos veces falla con "Port is already in use". Consulta [Grupos de dispositivos](/docs/device-groups).

## Dar a cada dispositivo sus propios argumentos

La mayoría de los bots necesitan un valor que cambia por cuenta: un nombre, un objetivo, un número de rondas. Hay dos formas de pasarlo.

**Perfiles de ajustes (sin cambiar código).** Si la macro tiene un formulario de argumentos hecho con UI Builder, cada tarjeta de dispositivo tiene **Editar argumentos**. El diálogo lleva una barra **Perfil**: introduce los valores, elige **Guardar los valores actuales como perfil nuevo**, ponle nombre y haz clic en **Crear perfil**. Un dispositivo sigue un perfil, y editar el perfil actualiza todos los dispositivos que lo siguen en su próxima ejecución. "Default" existe siempre y no se puede borrar. Consulta [Perfiles de ajustes](/docs/settings-profiles) y [UI Builder](/docs/ui-builder).

**El puerto en el código.** El script puede preguntar en qué instancia está y elegir sus propios ajustes. No necesita formulario y es lo que hace el ejemplo del final.

```python
import mas

port = mas.get_current_device_port()   # 5555, 5557, 5559 ...
```

Usa perfiles cuando los valores cambian a menudo o cuando otra persona ejecuta el bot; usa el puerto cuando la correspondencia es fija y vive con el código.

## Dar a cada dispositivo su propio proxy

Las cuentas que comparten IP comparten destino. MAS asigna un proxy por dispositivo y enruta el tráfico de esa instancia a través de él.

1. Abre **Proxies**. En **Añadir un proxy**, rellena la pestaña **Cuenta del gateway**, o la pestaña **Otro proveedor** para un proxy propio (`http`, `https` o `socks5`), y haz clic en **Añadir y probar**.
2. Espera a la prueba. Confirma que el proxy responde y detecta su país; **Probar** la repite más adelante.
3. Haz clic en **Asignar** y elige el dispositivo, o abre la tarjeta del dispositivo en **Grupos de dispositivos** y elige el proxy en **Proxy**.

La tarjeta del dispositivo muestra el estado del proxy en cada ejecución, y los webhooks de ejecución llevan `proxy_exit_ip` y `proxy_country`. Un dispositivo tiene un solo proxy; asignar otro sustituye al anterior. Consulta [Proxies](/docs/proxies).

## Iniciar todos: sincronizar instancias de LDPlayer o BlueStacks

Haz clic en **Iniciar todos** en la parte superior del grupo. MAS arranca los dispositivos uno tras otro, con medio segundo de separación, cada uno con su propia ejecución, su propio log y su propio código de salida. Un dispositivo sin macro se omite con un error y el resto continúa. **Detener todos** termina todas las ejecuciones del grupo. La pestaña **Logs** de cada tarjeta muestra solo ese dispositivo, y la pestaña **Panel** muestra su interfaz en tiempo de ejecución si la macro tiene una.

## Mantener el estado por dispositivo con el almacenamiento

`mas.save`, `mas.retrieve` y `mas.clear` se indexan por este ordenador, el puerto del dispositivo y un nombre de tarea. Dos instancias que ejecutan la misma macro mantienen así contadores separados sin código adicional. Para sumarlos, `mas.retrieve_all(task_name)` devuelve una entrada por puerto con `machine_id`, `port`, `data` y `updated_at`.

```python
TASK = "collector"

mine = mas.retrieve(TASK)                          # this instance only
everyone = mas.retrieve_all(TASK)                  # every instance on this computer
total = sum(entry["data"].get("done", 0) for entry in everyone)
```

Consulta [Almacenamiento](/docs/sdk/storage).

## Webhooks por grupo

Para enterarte de cuándo termina o falla cualquier cuenta, añade un endpoint en la página **Webhooks**, elige los eventos en **Enviarme** y, en **Enviarme eventos de**, elige **Grupos concretos** y marca el grupo. Los dispositivos que añadas al grupo más tarde también quedan cubiertos. Cada evento lleva `device_name`, `device_port`, `group_id`, `status` y `exit_code`, así que un solo endpoint puede distinguir las cuentas. Consulta [Webhooks](/docs/webhooks).

## Vigilar los límites de recursos de una granja de bots en BlueStacks

Cada instancia es un sistema Android completo. Antes de escalar, comprueba tres cosas:

- **CPU y RAM por instancia.** Cada instancia toma los núcleos y la memoria fijados en los ajustes de instancia del emulador. Súmalos y deja margen para MAS, que ejecuta la coincidencia de plantillas y el OCR de todas las instancias en la misma máquina. Cuando los toques empiezan a llegar tarde, te has pasado.
- **Dispositivos de tu plan.** Un plan se dimensiona por cuántos de tus propios dispositivos pueden ejecutarse a la vez. **Iniciar todos** ejecuta tantos como permita el plan; consulta [Facturación](/docs/billing) y la [página de precios](/pricing).
- **Tareas programadas.** El Programador ejecuta hasta 20 tareas a la vez, una por puerto.

Menos instancias funcionando limpiamente valen más que muchas instancias fallando plantillas.

## Programar el grupo

El Programador apunta a un puerto por tarea, así que la programación de un grupo es una tarea por dispositivo.

1. Abre **Programador** y haz clic en **Crear nueva programación**.
2. Elige la **Macro**, haz clic en **Escanear** en **Puerto del emulador** y elige la primera instancia.
3. Fija la **Fecha**, la **Hora** y la **Recurrencia**, y haz clic en **Crear programación**.
4. Repite con cada puerto. Da a las tareas la misma hora; puertos distintos nunca chocan.

Las ejecuciones programadas usan los argumentos guardados en cada tarjeta de dispositivo, o el perfil que sigue el dispositivo, así que los valores por cuenta se mantienen. La app debe seguir abierta. Consulta [Programador](/docs/scheduler) y la [guía de bucles](/docs/guides/loops-and-scheduling).

## Un ejemplo completo

La macro lee su puerto, elige los ajustes de la cuenta, mantiene un contador por puerto y registra al final el total de todas las instancias. Sustituye los puertos y los ID de imagen por los tuyos.

```python
import random
import sys
import time

import mas

images = mas.images({
    "collect": 501,
    "close_popup": 502,
})

SETTINGS = {   # per instance, keyed by the emulator's adb port
    5555: {"account": "main", "rounds": 20},
    5557: {"account": "alt-1", "rounds": 10},
    5559: {"account": "alt-2", "rounds": 10},
}
DEFAULT = {"account": "unknown", "rounds": 5}
TASK = "collector"
TIME_BUDGET_S = 15 * 60


def main():
    port = mas.get_current_device_port()
    settings = SETTINGS.get(port, DEFAULT)
    account = settings["account"]
    mas.log(f"Port {port}: account {account}, {settings['rounds']} rounds")

    done = mas.retrieve(TASK).get("done", 0)
    started = time.monotonic()
    misses = 0

    while done < settings["rounds"]:
        if time.monotonic() - started > TIME_BUDGET_S:
            mas.log(f"{account}: time budget reached", level="warning")
            break
        popup = mas.find_object(images.close_popup)
        if popup:
            mas.click(popup.x, popup.y, delay_ms=800)
            continue
        button = mas.find_object_retry(images.collect, total_tries=3, time_sleep=2.0)
        if button is None:
            misses += 1
            if misses >= 5:
                mas.log(f"{account}: five misses, giving up", level="error")
                sys.exit(2)
            continue
        misses = 0
        mas.click(button.x, button.y, delay_ms=1000)
        done += 1
        mas.save(TASK, {"done": done, "account": account})
        time.sleep(random.uniform(0.8, 2.5))

    total = sum(entry["data"].get("done", 0) for entry in mas.retrieve_all(TASK))
    mas.log(f"{account}: {done} rounds done; {total} across all instances")
    mas.webhook("account.finished", {"account": account, "port": port, "done": done})


if __name__ == "__main__":
    main()
```

`mas.webhook` envía un evento `custom.account.finished` a los endpoints suscritos a eventos personalizados; quita la línea si no tienes ninguno. Cuando la correspondencia crezca, pásala a un formulario de argumentos y lee `args.<tab>.<key>` en lugar del diccionario.

## Qué puede salir mal

### Port is already in use

Otro dispositivo de uno de tus grupos tiene ese puerto. Cada puerto se puede añadir una sola vez; quita la entrada antigua o elige el puerto de la otra instancia.

### Una instancia funciona y las demás se quedan en Conectando

Las otras instancias tienen ADB apagado, siguen arrancando o escuchan en puertos fuera del rango del emulador. Abre los ajustes de cada instancia, confirma ADB y el puerto, y haz clic en **Actualizar** en **Añadir dispositivo**. Si el puerto queda fuera de la tabla de arriba, usa **Puerto personalizado**. Consulta [Solución de problemas de ADB](/docs/adb-troubleshooting).

### Las plantillas solo coinciden en una instancia

Esa instancia tiene otra resolución u otro DPI. La coincidencia de plantillas se basa en píxeles; pon todas las instancias a la resolución de captura en los ajustes de instancia del emulador y reinícialas. La [guía de reconocimiento de imagen](/docs/guides/image-recognition-macros) explica el resto.

### Todas las instancias comparten un contador

El script pasa un `port` o un `machine_id` explícito a `mas.save`, o usa un archivo en disco en lugar del almacenamiento. Llama a `mas.save(TASK, data)` con los valores por defecto; el puerto actual se añade por ti.

Ninguna herramienta de automatización está libre de riesgos al 100 %, así que automatiza con responsabilidad y bajo tu propio criterio.
