Saltar al contenido
Todas las guías
Guía práctica45 min de lectura

Cómo automatizar capturas de pantalla de la App Store en CI/CD

Un pipeline práctico de extremo a extremo para generar capturas de pantalla de la App Store y Google Play desde tu sistema de CI utilizando Fastlane, GitHub Actions y Bitrise — con configuración concreta que puedes pegar directamente en tu repositorio.

Eric Isensee
Eric IsenseeFounder · Last updated 5 de mayo de 2026

Resumen

Captura screenshots brutos de la app en tu test runner, envíalos a la API de Screenshots.live con un ID de plantilla y una lista de idiomas, y Fastlane escribe el resultado renderizado, enmarcado y localizado de vuelta en tu repositorio. Fastlane deliver / supply los publica en las tiendas. Todo el pipeline corre en un push de tag o en un cron nocturno en menos de cinco minutos.

¿Por qué automatizar las capturas de pantalla?

La mayoría de los equipos tratan las capturas de pantalla de la App Store y Google Play como un activo único, hecho a mano: un diseñador las maqueta en Figma, un responsable de marketing las sube a App Store Connect y nadie las vuelve a tocar hasta el siguiente rediseño importante. Ese modelo se rompe en el momento en que publicas para más de un idioma. Con 13 idiomas soportados, tres tamaños obligatorios de iPhone, dos tamaños de iPad, además de teléfono y tablet en Google Play, te encuentras con más de 100 archivos PNG para una sola release. Multiplica eso por cada cambio de copy, cada promoción, cada variante de A/B test, y las cuentas dejan de cuadrar.

Automatizar en CI/CD convierte las capturas de pantalla en un artefacto de build como cualquier otro binario. Quedan versionadas, son reproducibles y están vinculadas a un commit. Cuando marketing cambia un texto, el pipeline reconstruye cada idioma y los sube — sin sesiones manuales de Photoshop, sin desincronizaciones de assets entre idiomas, sin rechazos en la entrega porque alguien olvidó la variante de iPhone de 6,7 pulgadas.

¿Cómo es realmente el pipeline?

La forma de un pipeline de capturas en CI bien diseñado tiene tres etapas: capturar, renderizar y entregar. La captura es tu suite de tests de UI ya existente — XCUITest en iOS, Espresso en Android, Detox o Maestro para React Native. El renderizado es una llamada a la API de Screenshots.live por cada idioma que compone tus frames brutos sobre una plantilla que diseñaste una sola vez. La entrega son las acciones existentes de Fastlane deliver y supply que ya usas para publicar binarios.

La API REST de renderizado de Screenshots.live es la pieza clave. Envías capturas brutas una vez y recibes de vuelta cada tamaño de dispositivo, cada idioma y cada variante — totalmente enmarcados, con texto y localizados. Sin navegador headless, sin Puppeteer, sin redimensionado manual.

¿Cómo lo conectas con Fastlane?

Fastlane es la herramienta canónica de automatización de releases para iOS y Android. Publicamos un plugin oficial de Fastlane que envuelve la API de renderizado en una sola acción. Instálalo desde la raíz de tu proyecto:

terminal
bash
fastlane add_plugin screenshotslive

Después añade un lane a tu Fastfile que capture, renderice y escriba el resultado renderizado:

fastlane/Fastfile
ruby
lane :render_screenshots do
  # 1. Capture raw frames with XCUITest
  capture_screenshots(
    workspace: "MyApp.xcworkspace",
    scheme: "MyAppUITests",
    devices: ["iPhone 16 Pro Max", "iPad Pro 12.9-inch"],
    languages: ["en-US", "de-DE", "es-ES", "fr-FR", "pt-BR"]
  )

  # 2. Send raw frames to Screenshots.live, get framed PNGs back
  screenshotslive_render(
    api_token: ENV["SCREENSHOTSLIVE_API_TOKEN"],
    template_id: "tpl_app_release_v3",
    input_dir: "./fastlane/screenshots",
    output_dir: "./fastlane/rendered",
    locales: ["en", "de", "es", "fr", "pt"],
    devices: ["iphone-6.7", "iphone-6.1", "ipad-12.9"]
  )

  # 3. Push to App Store Connect
  deliver(
    screenshots_path: "./fastlane/rendered",
    skip_binary_upload: true,
    skip_metadata: false
  )
end

El plugin gestiona las subidas, el polling de finalización y la descarga en paralelo. Un renderizado típico de 5 idiomas y 3 dispositivos termina en 60–90 segundos.

¿Cómo se ejecuta esto en GitHub Actions?

Lleva el lane a un archivo de workflow. El workflow de abajo se ejecuta en cada push de tag que coincida con v* y en una programación nocturna, así que un simple git tag v1.2.0 && git push --tags manual es todo lo que necesitas para disparar un nuevo renderizado.

.github/workflows/screenshots.yml
yaml
name: Render Store Screenshots

on:
  push:
    tags: ["v*"]
  schedule:
    - cron: "0 4 * * *"  # nightly at 04:00 UTC
  workflow_dispatch:

jobs:
  render:
    runs-on: macos-14
    steps:
      - uses: actions/checkout@v4

      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.2"
          bundler-cache: true

      - name: Render screenshots
        env:
          SCREENSHOTSLIVE_API_TOKEN: ${{ secrets.SCREENSHOTSLIVE_API_TOKEN }}
          FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
          FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
        run: bundle exec fastlane render_screenshots

      - name: Upload rendered artifacts
        uses: actions/upload-artifact@v4
        with:
          name: store-screenshots
          path: fastlane/rendered/

Para los equipos que prefieren una GitHub Action sin Fastlane, también publicamos una GitHub Action independiente que habla directamente con la API:

.github/workflows/screenshots-direct.yml
yaml
- uses: Screenshots-Live/render-screenshots-action@v1
  with:
    api-token: ${{ secrets.SCREENSHOTSLIVE_API_TOKEN }}
    template-id: tpl_app_release_v3
    locales: en,de,es,fr,pt,it,nl
    devices: iphone-6.7,iphone-6.1,ipad-12.9
    output-dir: ./screenshots

¿Y con Bitrise?

Los usuarios de Bitrise obtienen el mismo lane a través del paso existente de Fastlane. Añade un Secret llamado SCREENSHOTSLIVE_API_TOKEN en tu workspace de Bitrise y luego incluye esto en tu bitrise.yml:

bitrise.yml
yaml
workflows:
  render-screenshots:
    steps:
    - activate-ssh-key@4: {}
    - git-clone@8: {}
    - script@1:
        title: Install Fastlane plugins
        inputs:
        - content: |-
            #!/usr/bin/env bash
            bundle install
            bundle exec fastlane add_plugin screenshotslive
    - fastlane@3:
        inputs:
        - lane: render_screenshots
        - work_dir: "$BITRISE_SOURCE_DIR"
    - deploy-to-bitrise-io@2:
        inputs:
        - deploy_path: ./fastlane/rendered

¿Cómo mantienes bajos los tiempos de build?

La parte lenta de cualquier pipeline de capturas en CI es el renderizado, no la subida. El truco está en cachear los renderizados por hash de contenido para que los idiomas que no cambian reutilicen la salida anterior. Screenshots.live devuelve un renderHash estable en la respuesta — úsalo como clave de caché:

  • Versión de plantilla + idioma + hash de variante → clave de caché
  • Bytes del PNG renderizado → valor de caché
  • TTL de caché: 30 días, o hasta que la plantilla se vuelva a publicar

En GitHub Actions, usa actions/cache@v4 con una clave derivada del ID de tu plantilla y la lista de idiomas. La mayoría de las builds de release saltan el renderizado por completo y solo regeneran el idioma que realmente cambió.

¿Cómo validas la salida antes de enviarla?

Apple y Google rechazan las capturas en silencio cuando fallan las comprobaciones de formato: un PNG con canal alfa, un JPEG codificado como CMYK o una captura de iPhone de 6,7 pulgadas con un píxel de menos. Construye un paso de lint de 20 líneas que detecte estos errores antes del envío:

fastlane/lint_screenshots.rb
ruby
require "chunky_png"

Dir.glob("./fastlane/rendered/**/*.png").each do |path|
  png = ChunkyPNG::Image.from_file(path)
  raise "alpha channel: #{path}" if png.metadata["ColorType"] == 6
  raise "too large: #{path}"     if File.size(path) > 30 * 1024 * 1024
  raise "wrong size: #{path}"    if png.width < 1242
end

¿Deberías ejecutarlo de forma programada?

Sí. Un cron nocturno significa que las capturas se regeneran cada vez que tu plantilla cambia — ya sea por un cambio de un diseñador en el editor, una actualización de copy de marketing o la incorporación de un nuevo idioma. Sin programación, las fichas en las tiendas se desincronizan de tu producto real, y alguien tiene que acordarse de lanzar una build nueva antes de cada envío.

Combina la programación con una alerta por Slack o por correo electrónico ante fallos. Un renderizado roto a las 04:00 UTC se convierte en una notificación a las 07:00 hora local — no en un bloqueo de release descubierto a las 17:00 del día en que querías publicar.

¿Y con Android, React Native y Flutter?

El pipeline es independiente de la plataforma en el lado del renderizado — solo cambia la fase de captura. Para Android, sustituye capture_screenshots por Fastlane screengrab y tu suite de Espresso. Para React Native, usa snapshots de Detox. Para Flutter, usa capturas de integration_test. Todas producen PNGs brutos que Screenshots.live trata por igual.

Lee más en nuestra guía de soporte multiplataforma para la configuración de captura en cada stack.

¿Hacia dónde ir desde aquí?

Una vez que tu pipeline de CI publique capturas de forma fiable, la siguiente pregunta es qué capturas ganan. Combina este pipeline con la guía de A/B testing para lanzar variantes de forma programada y medir la conversión. Combínalo con la guía de localización para añadir más de 30 idiomas sin tener más de 30 pipelines.

Referencias autorizadas para profundizar: documentación de capturas de Fastlane para iOS, acción Fastlane deliver y las especificaciones oficiales de capturas de App Store Connect.

Pruébalo en un repositorio real

Genera todos estos tamaños automáticamente

Deja de redimensionar capturas de pantalla manualmente. Diseña una sola plantilla y renderiza cada tamaño, dispositivo e idioma con una única llamada a la API.

Empieza gratis — Prueba Screenshots.live