ScreenShipper
Blog
Tools & Workflow

Automate Android Screenshots with fastlane screengrab

Set up fastlane screengrab to capture Android screenshots in every locale: Gradle dependency, manifest permissions, LocaleTestRule, Screengrabfile and output.

ScreenShipper team · · 7 min read

Quick answer: fastlane screengrab runs your instrumented Android tests on an emulator or device once per locale and saves a screenshot wherever a test calls Screengrab.screenshot("01_home"). Add the tools.fastlane:screengrab test dependency, a few debug-only manifest permissions and a LocaleTestRule, build with ./gradlew assembleDebug assembleAndroidTest, then run fastlane screengrab. Images land in fastlane/metadata/android.

How screengrab Works

screengrab is the Android counterpart of fastlane snapshot. It doesn't record taps or explore your app; it runs the instrumented tests you write, switching the device locale between runs.

One run looks like this:

  1. You build two APKs: your debug app and its instrumentation test APK.
  2. screengrab installs both on a connected emulator or device.
  3. For each locale in your list, it runs the tests. LocaleTestRule switches the app's locale before they start.
  4. Each Screengrab.screenshot() call captures the screen.
  5. screengrab pulls the images into fastlane/metadata/android, organized per locale in the folder layout fastlane's supply tool uploads from, such as en-US/images/phoneScreenshots.

Because the tests drive real UI, you can use Espresso, UI Automator or Compose test APIs to navigate. The Espresso documentation is the best starting point if you haven't written instrumented tests before.

Step 1: Add the Dependency and Permissions

Install fastlane with Bundler, Homebrew or RubyGems, then add the screengrab library to your app module's test dependencies:

  • Groovy: androidTestImplementation 'tools.fastlane:screengrab:x.x.x'
  • Kotlin DSL: androidTestImplementation("tools.fastlane:screengrab:x.x.x")

Replace x.x.x with the latest version listed in the fastlane docs. Since screengrab 2.0.0, its test dependencies use AndroidX. Your defaultConfig should use androidx.test.runner.AndroidJUnitRunner as the testInstrumentationRunner, which is also screengrab's default.

Next, add permissions to src/debug/AndroidManifest.xml, so they only exist in debug builds and never reach your release app. The screengrab action documentation lists:

  • android.permission.WRITE_EXTERNAL_STORAGE with android:maxSdkVersion="18", for storing screenshots where adb can reach them on old devices
  • android.permission.CHANGE_CONFIGURATION with tools:ignore="ProtectedPermissions", which lets screengrab change the locale
  • android.permission.DUMP with tools:ignore="ProtectedPermissions"

The tools:ignore attribute requires the tools namespace on the manifest element: xmlns:tools="http://schemas.android.com/tools". Older guides list a different set, including keyguard and wake lock permissions, so follow the docs for the screengrab version you install.

Step 2: Write the Screenshot Test

Create a JUnit 4 test class under src/androidTest. It needs two rules: one to set the locale and one to launch your activity.

  • Java: @ClassRule public static final LocaleTestRule localeTestRule = new LocaleTestRule();
  • Kotlin: @Rule @JvmField val localeTestRule = LocaleTestRule()

In Kotlin, the docs stress that @JvmField is required and that declaring the rule in a companion object won't work. For launching, the docs' examples use ActivityScenarioRule<MainActivity>; in Kotlin that's @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java).

Then navigate and capture:

  1. Wait for the first screen to load and call Screengrab.screenshot("01_home").
  2. Perform an action with Espresso, such as onView(withId(R.id.search)).perform(click()).
  3. Call Screengrab.screenshot("02_search"), and so on for each screen you want.

Numeric prefixes keep the files in gallery order.

Screenshot strategy and status bar

In screengrab 2.x, the default capture strategy uses UI Automator, which requires API level 18 or higher and captures the whole screen, including dialogs. For very old devices, the docs point to the 1.x library with DecorViewScreenshotStrategy.

For a tidy status bar, call CleanStatusBar.enableWithDefaults() in a @BeforeClass method and CleanStatusBar.disable() in @AfterClass. This works on API level 23 and higher. Our clean status bar guide also covers Android's demo mode if you capture screens by hand.

Step 3: Build the APKs and Configure the Screengrabfile

Build both APKs with ./gradlew assembleDebug assembleAndroidTest. With a standard Gradle setup, they appear at app/build/outputs/apk/debug/app-debug.apk and app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk.

Run fastlane screengrab init to generate a Screengrabfile. The template sets locales(["en-US", "fr-FR", "it-IT"]) and clear_previous_screenshots(true) and includes commented-out lines for package names and APK paths. The options you'll use most:

OptionExample or defaultPurpose
localeslocales(["en-US", "de-DE", "ja-JP"])Locales to capture; default is en-US
app_package_nameapp_package_name("com.example.app")The app under test
app_apk_path / tests_apk_pathpaths from your Gradle buildWhich APKs to install
use_tests_in_packages / use_tests_in_classesyour screenshot test package or classRun only screenshot tests, not your whole suite
clear_previous_screenshotstrueRemove old images first
output_directorydefault fastlane/metadata/androidWhere images are saved
device_typedefault phoneGoogle Play type: phone, sevenInch, tenInch, tv or wear
specific_devicean adb devices serialPick one device when several are connected
use_timestamp_suffixdefault trueAdds a timestamp to file names
launch_argumentslaunch_arguments(["demo_mode true"])Values your tests read with InstrumentationRegistry.getArguments()
exit_on_test_failuretrue or falseWhether a failing test stops the run

Set use_timestamp_suffix(false) if you want stable file names that overwrite each run. Options such as ending_locale and use_adb_root are deprecated, so leave them out of new setups. Run fastlane action screengrab to see the full list for your version.

Step 4: Run screengrab and Upload

Start an emulator from Android Studio's Device Manager, or connect a phone with USB debugging enabled, then run fastlane screengrab from the project folder. screengrab works on emulators and real devices.

For tablets, run it again on a tablet emulator with device_type set to sevenInch or tenInch, so the images land in the matching folders. Google recommends at least four large-screen screenshots for tablet visibility; our tablet screenshot guide explains why.

To automate the whole flow, put it in a lane: build_android_app(task: "assemble", build_type: "Debug"), then build_android_app(task: "assemble", build_type: "AndroidTest"), then capture_android_screenshots, then upload_to_play_store. To upload screenshots on their own, fastlane supply reads the same fastlane/metadata/android folder.

Make the Captures Google Play Ready

Raw captures often can't be uploaded unchanged. Google Play currently requires:

  • 2 to 8 screenshots per device type to publish
  • JPEG or 24-bit PNG with no alpha channel, up to 8 MB each
  • Each side between 320 and 3840 pixels
  • A long side no more than twice the short side

That last rule catches many teams. Current phones often have tall screens such as 1080 × 2400, which is more than 2 to 1, so a full-screen capture can fail the check. Place the capture inside a designed canvas, such as 1080 × 1920, with a headline and device frame. Screenshots at least 1080 pixels on the short side are also what Google looks for when deciding eligibility for featured placements. The Google Play screenshot sizes guide and Google Play screenshot requirements have the details.

If you want framing inside fastlane, fastlane frameit android adds device frames; see our frameit guide. For a designed set in many languages, use the captures as source images in your design tool.

Troubleshooting screengrab

ProblemWhat to check
Every screenshot is in EnglishCHANGE_CONFIGURATION is in the debug manifest; the locale rule is declared as shown above
Kotlin locale rule has no effectUse @Rule @JvmField, not a companion object
Tests not foundapp_package_name, tests_apk_path and the instrumentation runner match your build
Wrong device usedSet specific_device to the serial from adb devices
Status bar shows notificationsEnable CleanStatusBar (API 23 and higher)
Dialogs missing from capturesMake sure you're on the UI Automator strategy

Frequently Asked Questions

Does screengrab work with Jetpack Compose?

Yes. Compose UI tests are instrumented tests, so you can call Screengrab.screenshot() from them, and the default UI Automator strategy captures the whole screen regardless of how it was drawn.

Can I use screengrab with Flutter or React Native?

screengrab is built for native instrumented tests. Flutter apps usually capture screenshots with the integration_test package instead; see Flutter App Store screenshots.

Is screengrab the Android version of fastlane snapshot?

Yes. snapshot drives Xcode UI tests on iOS simulators, while screengrab drives instrumented tests on Android. Our fastlane snapshot guide covers the iOS side.

Where does screengrab save the screenshots?

In fastlane/metadata/android inside the folder where you ran it, split by locale and device type. That's the structure fastlane supply uploads from.

Sources

From raw captures to store-ready screenshots

Drop your simulator or emulator captures into a template and export every store size, or frame a single screen with the free mockup generator.

All guides