Scripts personalizados
Los scripts integrados cubren los flujos habituales. Cuando necesitas algo que no ofrecen —un paso en otro orden, una pantalla que nunca tocan o una app que no es TikTok ni Instagram— puedes escribirlo tú mismo en cualquier lenguaje y dejar que TikMatrix te entregue el teléfono.
Requisitos
Los scripts personalizados requieren un plan Pro, Team o Business. El plan Starter no tiene acceso.
El número de dispositivos de tu plan es también el límite de concurrencia: un plan Pro (20 dispositivos) puede controlar 20 teléfonos a la vez, ya sea mediante tareas integradas, scripts personalizados o una mezcla de ambos.
Dos formas de ejecutar un script
Autónoma
Tú ejecutas tu programa. TikMatrix solo te presta los dispositivos.
from tikmatrix import TikMatrix
client = TikMatrix()
for device in client.devices():
if device["busy"]:
continue
with client.device(device["serial"], label="my crawler") as d:
d.press("home")
print(d.info())
Ideal para trabajos puntuales, recolección de datos y todo lo que quieras lanzar desde tu propio planificador.
Gestionada
Registras el programa en TikMatrix y se convierte en una tarea más. Obtiene la cola de tareas, la concurrencia según el plan, los reintentos automáticos, el registro de tareas y las plantillas de programación. TikMatrix arrienda el dispositivo antes de arrancar tu programa y le pasa el id del arriendo en el entorno.
from tikmatrix import TikMatrix
with TikMatrix.from_env() as d: # el dispositivo ya está arrendado
d.click(text="Log in")
print("done") # esta línea acaba en el registro de la tarea
Ideal para todo lo que quieras ejecutar de forma repetida, programada o en muchos dispositivos.
Cuál elegir
| Autónoma | Gestionada | |
|---|---|---|
| Quién la arranca | Tú | La cola de tareas de TikMatrix |
| Arriendo del dispositivo | Lo pides tú | Ya está tomado al arrancar |
| Reintentos, programación, registro | Los construyes tú | Incluidos |
| Ejecución en muchos dispositivos | Escribes el bucle tú | Una tarea por dispositivo, en paralelo |
| Mejor para | Exploración, rastreadores, trabajos puntuales | Todo lo que quieras repetir |
Puedes empezar en modo autónomo mientras afinas el flujo y luego registrar el mismo archivo como script gestionado: la única línea que cambia es TikMatrix.from_env().
Primeros pasos
1. Instala la librería cliente
pip install requests
Después copia tikmatrix.py del directorio del SDK junto a tu script. La librería es un único archivo sin más dependencias.
No estás obligado a usarla: la API es JSON plano sobre HTTP y los endpoints en crudo están documentados más abajo.
2. Escribe tu script
from tikmatrix import TikMatrix
client = TikMatrix()
with client.device("192.168.1.5:5555") as d:
d.press("home")
d.adb("shell", "am", "start", "-a", "android.settings.SETTINGS")
d.wait_for(text="Settings", timeout=15)
d.screenshot("settings.png")
Ejecútalo con TikMatrix abierto y el teléfono conectado. Si imprime un diccionario con la información del dispositivo, todo está conectado correctamente.
3. Regístralo (solo modo gestionado)
Ve a Dispositivos → Scripts personalizados → Añadir script:
| Campo | Significado |
|---|---|
| Nombre | Se muestra en la lista de scripts y en el registro de tareas |
| Comando | La línea del programa a ejecutar, p. ej. python C:/scripts/my_flow.py |
| Directorio de trabajo | Opcional. Dónde arranca el programa |
| Plataforma | Consulta modos de plataforma más abajo |
| Tiempo de espera | Segundos antes de matar el script y marcar la tarea como fallida. Por defecto 1800 |
| Variables de entorno adicionales | Objeto JSON opcional que se fusiona con el entorno del programa |
| Habilitado | Desactiva un script sin borrarlo. Un script deshabilitado no puede despacharse |
Después pulsa ▶ en la fila del script y elige tus dispositivos, exactamente igual que con un script integrado.
El Asistente de IA puede redactar un script personalizado a partir de una descripción en lenguaje corriente y registrarlo en un solo paso. Te muestra el archivo completo antes de escribir nada en disco.
Arriendos de dispositivo
Un teléfono solo puede ser controlado por una cosa a la vez. Arrendarlo le indica a TikMatrix que el dispositivo está ocupado, de modo que:
- la cola de tareas no despachará una tarea sobre la misma pantalla, y
- tus llamadas JSON-RPC informan del estado del agente igual que lo hace un script integrado, así que el watchdog ve un agente ocupado en lugar de uno mudo.
Un arriendo también consume una plaza de dispositivo de tu plan.
Los arriendos caducan: 120 segundos por defecto, 600 como máximo. La librería de Python renueva el tuyo en un hilo en segundo plano y lo libera al salir del bloque with, de modo que un script que se cae libera su dispositivo en segundos en vez de retenerlo hasta que reinicies la app. Si llamas a la API directamente, tendrás que enviar los latidos tú mismo.
Puedes ver todos los arriendos activos —y liberar uno a la fuerza— en Ajustes → Developer API → Sesiones de dispositivo activas.
Modos de plataforma
Un script registrado declara a qué apunta:
Generic — el dispositivo se entrega intacto. No se abre ninguna app, no hay cambio de cuenta, no se comprueba el método de entrada y no se cierra nada al terminar. Úsalo para automatizar cualquier cosa que no sea TikTok ni Instagram.
TikTok / Instagram — la app se abre y la cuenta se cambia antes de que arranque tu programa, y la app se cierra al terminar, exactamente igual que con un script integrado. TIKMATRIX_PACKAGE te dice qué paquete se resolvió. Úsalo para añadir un paso que los scripts integrados no cubren.
Variables de entorno
Un script gestionado recibe:
| Variable | Significado |
|---|---|
TIKMATRIX_API_BASE | URL del servidor, p. ej. http://127.0.0.1:50809 |
TIKMATRIX_SESSION_ID | El arriendo ya tomado en tu nombre |
TIKMATRIX_SERIAL | El dispositivo al que se despachó esta tarea |
TIKMATRIX_PACKAGE | Paquete de app resuelto |
TIKMATRIX_PLATFORM | tiktok, instagram o generic |
TikMatrix.from_env() lee todo esto por ti.
Los scripts autónomos no reciben ninguna de ellas: arrienda un dispositivo explícitamente.
Todo lo que pongas en Variables de entorno adicionales se fusiona por encima, que es la forma habitual de dar ajustes por ejecución a un mismo script registrado sin editar el archivo.
Referencia de la librería de Python
TikMatrix — la conexión
| Llamada | Qué hace |
|---|---|
TikMatrix(base_url=None, timeout=30.0) | Conecta. Recurre a TIKMATRIX_API_BASE y luego a http://127.0.0.1:50809 |
client.devices() | Dispositivos en línea, cada uno con serial, real_serial y busy |
client.sessions() | Todos los arriendos activos, incluidos los de otros procesos |
client.device(serial, label=..., ttl_secs=120) | Arrienda un dispositivo y devuelve un Device |
TikMatrix.from_env() | Adopta el dispositivo con el que arrancó un script gestionado |
Device — el teléfono
| Llamada | Qué hace |
|---|---|
d.info() | Información del dispositivo de UIAutomator2 |
d.window_size() | (ancho, alto) |
d.screenshot(path=None) | Bytes PNG, opcionalmente escritos en path |
d.hierarchy() | El árbol de UI actual en XML |
d.find(text=, resource_id=, description=, class_name=) | Nodos coincidentes, cada uno con bounds y center |
d.exists(**criteria) | Si hay alguna coincidencia |
d.wait_for(timeout=10.0, interval=1.0, **criteria) | Espera hasta que aparezca y lo devuelve |
d.click(timeout=10.0, **criteria) | Espera un elemento y toca su centro |
d.click_xy(x, y) | Toca una coordenada |
d.swipe(sx, sy, ex, ey, steps=20) | Desliza |
d.press(key) | back, home, recent, enter, … |
d.input_text(text) | Escribe en el campo enfocado con el IME rápido incluido |
d.jsonrpc(method, params=None, timeout=10) | Cualquier método de UIAutomator2 |
d.adb(*args, timeout_ms=None) | Ejecuta un comando ADB |
d.release() | Libera el arriendo. with lo hace por ti |
find busca sobre el árbol de UI volcado, así que cuando un selector falla puedes hacer print(d.hierarchy()) y ver exactamente qué se buscó. El Inspector de elementos en la vista del dispositivo muestra el mismo árbol de forma visual, que suele ser la manera más rápida de encontrar un resource-id.
input_text necesita ADBEnvía un broadcast al método de entrada incluido, que pasa por adb shell. Habilita el acceso ADB antes de usarlo o fallará con 403.
Errores
La librería lanza dos excepciones, ambas subclases de RuntimeError:
| Excepción | Cuándo |
|---|---|
DeviceBusyError | HTTP 409: el dispositivo ya está arrendado o tu plan no tiene plazas libres |
TikMatrixError | Todo lo demás: plan insuficiente, arriendo caducado, ADB deshabilitado, selector que nunca coincidió |
from tikmatrix import TikMatrix, TikMatrixError, DeviceBusyError
client = TikMatrix()
try:
with client.device("192.168.1.5:5555") as d:
d.click(text="Log in", timeout=20)
except DeviceBusyError:
print("ese teléfono lo tiene otro proceso: prueba con otro")
except TikMatrixError as exc:
print("falló:", exc)
En un script gestionado, dejar que la excepción escape suele ser lo correcto: la salida distinta de cero marca la tarea como fallida y la traza acaba en el registro de la tarea.
Endpoints HTTP
Las operaciones de dispositivo necesitan una cabecera x-session-id que nombre un arriendo activo. No hay clave de API: como el resto de la API local, estos endpoints no están autenticados; poder alcanzar la máquina en la red es el control de acceso. No envían cabeceras CORS, así que llámalos desde un programa (curl, Python, cualquier código de servidor) y no desde una página del navegador.
| Método | Ruta | Propósito |
|---|---|---|
GET | /api/v1/rpc/devices | Lista los dispositivos en línea y si están ocupados |
POST | /api/v1/rpc/session | Arrienda un dispositivo → session_id |
POST | /api/v1/rpc/session/{id}/heartbeat | Extiende el arriendo |
DELETE | /api/v1/rpc/session/{id} | Libera el arriendo |
GET | /api/v1/rpc/session | Lista los arriendos activos |
POST | /api/v1/rpc/jsonrpc | Llama a un método de UIAutomator2 |
POST | /api/v1/rpc/adb | Ejecuta un comando ADB |
GET | /api/v1/rpc/hierarchy?serial= | Árbol de UI actual en XML |
GET | /api/v1/rpc/screenshot?serial= | Pantalla actual en PNG |
Las respuestas JSON usan el mismo sobre que el resto de la API local —{"code": 0, "message": "success", "data": ...}, con code distinto de cero en caso de fallo—. hierarchy y screenshot devuelven el cuerpo en crudo.
Ejemplo
# Arrendar un dispositivo
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session \
-H "Content-Type: application/json" \
-d '{"serial":"192.168.1.5:5555","label":"curl test","ttl_secs":120}'
# {"code":0,"message":"success","data":{"session_id":"ff3ae079-...","serial":"192.168.1.5:5555", ...}}
# Controlarlo
curl -X POST http://127.0.0.1:50809/api/v1/rpc/jsonrpc \
-H "x-session-id: ff3ae079-..." \
-H "Content-Type: application/json" \
-d '{"serial":"192.168.1.5:5555","method":"deviceInfo","params":[]}'
# Mantenerlo vivo mientras trabajas
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-.../heartbeat \
-H "Content-Type: application/json" \
-d '{"ttl_secs":120}'
# Devolverlo
curl -X DELETE http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-...
Errores
| Estado | Significado |
|---|---|
| 403 | Plan inferior a Pro, sin arriendo, arriendo caducado o acceso ADB deshabilitado |
| 409 | Dispositivo ya arrendado, o tu plan no tiene plazas libres |
Escribir en otro lenguaje
Aquí no hay nada específico de Python. Sirve cualquier entorno capaz de hacer una petición HTTP: el contrato del modo gestionado es solo «lee tres variables de entorno y sal con 0 si todo fue bien».
// my_flow.js — regístralo con: node C:/scripts/my_flow.js
const base = process.env.TIKMATRIX_API_BASE || "http://127.0.0.1:50809";
const serial = process.env.TIKMATRIX_SERIAL;
const session = process.env.TIKMATRIX_SESSION_ID;
async function jsonrpc(method, params = []) {
const res = await fetch(`${base}/api/v1/rpc/jsonrpc`, {
method: "POST",
headers: { "content-type": "application/json", "x-session-id": session },
body: JSON.stringify({ serial, method, params }),
});
const body = await res.json();
if (!res.ok || body.code !== 0) throw new Error(body.message || res.statusText);
return body.data;
}
console.log(await jsonrpc("deviceInfo"));
Si el intérprete no está en el PATH, indica su ruta completa en Comando, p. ej. C:/Program Files/nodejs/node.exe C:/scripts/my_flow.js.
Lanzar un script personalizado desde la API
Los scripts registrados también se pueden lanzar mediante la API de gestión de tareas, de modo que un script puede encolar trabajo posterior:
curl -X POST http://127.0.0.1:50809/api/v1/task \
-H "Content-Type: application/json" \
-d '{
"serials": ["192.168.1.5:5555"],
"script_name": "custom_script",
"script_config": {
"custom_script_id": 1,
"custom_script_platform": "generic"
}
}'
custom_script_id es el id del script que registraste.
Acceso ADB
/api/v1/rpc/adb da a tus scripts un shell del dispositivo: lo necesitas para subir material, instalar APK y cambiar ajustes del sistema. Como es un shell completo en un endpoint sin clave de API, viene desactivado. Actívalo en Ajustes → Developer API → Permitir comandos ADB cuando tengas un script que lo necesite; la automatización de UI a través de /rpc/jsonrpc funciona sin él.
Mientras está desactivado, /api/v1/rpc/adb responde 403 y el resto de la API sigue funcionando. Cada comando ADB que ejecuta un script queda escrito en tu archivo de registro.
Cómo escribir scripts que sigan funcionando
- Espera la pantalla, no duermas por ella.
d.wait_for(...)vuelve en cuanto el elemento está ahí; un sleep fijo es o más lento de lo necesario o demasiado corto en un mal día. - Comprueba antes de tocar. Un
d.exists(...)sobre un diálogo de consentimiento o un aviso de «ahora no» cuesta un volcado del árbol y salva una ejecución que si no habría tocado el vacío. - Imprime lo que hiciste. En modo gestionado, stdout es el registro de la tarea, y es el único rastro de una ejecución que nadie estaba mirando.
- Haz que reejecutar sea seguro. Un reintento vuelve a correr el programa entero, así que un script que publica debería comprobar si ya publicó en vez de asumir que empieza de cero.
- Un script, un trabajo. La concurrencia es por dispositivo, así que diez tareas pequeñas en diez teléfonos terminan mucho antes que un script recorriendo diez teléfonos en bucle.
Notas y límites
- El comando se ejecuta directamente, no a través de un shell, así que
&&y|se tratan como argumentos y no como operadores. Registracmd /c "..."(Windows) osh -c "..."(macOS) si quieres comportamiento de shell. - Entrecomilla las rutas con espacios:
"C:/Program Files/Python/python.exe" my_script.py. - Un script que supera su tiempo de espera se termina y la tarea se marca como fallida.
- Un código de salida distinto de cero marca la tarea como fallida; todo lo que el script escriba en stdout y stderr acaba en el registro de la tarea.
- Los scripts se ejecutan con los mismos permisos que TikMatrix. Registra solo programas que hayas escrito tú o en los que confíes.
Resolución de problemas
API access requires Pro or higher plan (403)
La licencia de esta máquina es Starter o está inactiva. Revisa Ajustes → Licencia.
Conexión rechazada en 127.0.0.1:50809
TikMatrix no está en ejecución, o corre como otro usuario. El servidor solo existe mientras la app está abierta.
409 en cada intento de arriendo O el teléfono está realmente ocupado —míralo en Ajustes → Developer API → Sesiones de dispositivo activas— o todas las plazas de dispositivo de tu plan ya están tomadas por tareas en ejecución.
El arriendo caduca en mitad de un paso largo
El TTL por defecto es de 120 s y la librería lo renueva en segundo plano, así que esto suele significar que el script bloqueó su hilo principal más tiempo que el TTL. Sube ttl_secs (hasta 600) o saca el trabajo largo de ese hilo.
d.adb(...) falla con 403
El acceso ADB está desactivado. Actívalo en Ajustes → Developer API → Permitir comandos ADB.
Un selector nunca coincide
print(d.hierarchy()) muestra el árbol exacto que buscó find. El texto se compara de forma exacta, así que un espacio de más o una etiqueta traducida son la causa habitual; buscar por resource_id es más estable que por text.
La tarea se marca fallida pero el teléfono se ve bien Lee el registro de la tarea. Una salida distinta de cero —incluida una excepción sin capturar al final de una ejecución correcta— marca la tarea como fallida aunque la automatización haya funcionado.
Siguientes pasos
- Visión general de la API local — autenticación y formato de respuesta
- API de gestión de tareas — crear, consultar, reintentar y detener tareas
- Asistente de IA — deja que un modelo redacte y registre un script por ti
- SDK y ejemplos en GitHub