Guides
Plan-enterprise-icon
Expo Application Services
API Reference

Take screenshot

Info-icon
So far, we have been using some third-party libraries such as react-native-gesture-handler, react-native-reanimated, and now react-native-view-shot. We can find hundreds of other third-party libraries on React Native Directory.

Step 1: Install libraries

To install both libraries, run the following commands:
Terminal
→ npx expo install react-native-view-shot expo-media-library

Step 2: Prompt for permissions

When creating an app that requires access to potentially sensitive information, such as access to the media library, we must first request the user's permission.
expo-media-library provides a usePermissions() hook that gives the permission status, and a requestPermission() method to ask for access to the media library when permission is not granted.
Initially, when the app loads for the first time and the permission status is neither granted nor denied, the value of the status is null. When asked for permission, a user can either grant the permission or deny it. We can add a condition to check if it is null, and if it is, trigger the requestPermission() method.
Add the following code snippet inside the <App> component:
App.js
import * as MediaLibrary from 'expo-media-library';

// ...rest of the code remains same

export default function App() {
  const [status, requestPermission] = MediaLibrary.usePermissions();
  // ...rest of the code remains same

  if (status === null) {
    requestPermission();
  }

  // ...rest of the code remains same
}
Once the permission is given, the value of the status changes to granted.

Step 3: Picking a library to take screenshots

To allow the user to take a screenshot within the app, we'll use react-native-view-shot. It allows capturing a <View> as an image.
Let's import it into App.js file:
App.js
import { captureRef } from 'react-native-view-shot';

Step 4: Create a ref to save the current view

The react-native-view-shot library provides a method called captureRef() that captures a screenshot of a <View> in the app and returns the URI of the screenshot image file.
To capture a <View>, wrap the <ImageViewer> and <EmojiSticker> components inside a <View> and then pass a reference to it. Using the useRef() hook from React, let's create an imageRef variable inside <App>.
App.js
import { useState, useRef } from 'react';

export default function App() {
  const imageRef = useRef();

  // ...rest of the code remains same

  return (
    <GestureHandlerRootView style={styles.container}>
      <View style={styles.imageContainer}>
        <View ref={imageRef} collapsable={false}>
          <ImageViewer placeholderImageSource={PlaceholderImage} selectedImage={selectedImage} />
          {pickedEmoji !== null ? (
            <EmojiSticker imageSize={40} stickerSource={pickedEmoji} />
          ) : null}
        </View>
      </View>
      /* ...rest of the code remains same */
    </GestureHandlerRootView>
  );
}
The collapsible prop is set to false in the above snippet because this <View> component is used to take a screenshot of the background image and the emoji sticker. The rest of the contents of the app screen (such as buttons) are not part of the screenshot.

Step 5: Capture a screenshot and save it

Now we can capture a screenshot of the view by calling the captureRef() method from react-native-view-shot inside the onSaveImageAsync() function. captureRef() accepts an optional argument where we can pass the width and height of the area we'd like to capture a screenshot for. We can read more about available options in the library's documentation.
The captureRef() method returns a promise that fulfills with the URI of the captured screenshot. We will pass this URI as a parameter to MediaLibrary.saveToLibraryAsync(), which will save the screenshot to the device's media library.
Update the onSaveImageAsync() function with the following code:
Take a screenshot
export default function App() {
  const onSaveImageAsync = async () => {
    try {
      const localUri = await captureRef(imageRef, {        
        height: 440,
        quality: 1,
      });

      await MediaLibrary.saveToLibraryAsync(localUri);      
      if (localUri) {
        alert("Saved!");
      }
    } catch (e) {
      console.log(e);
    }
  };
  // ...rest of the code remains same
}
Now, choose a photo and add a sticker. Then tap the “Save” button. We should see the following result:

Up next

The react-native-view-shot and expo-media-library work only on Android and iOS, but we'd like our app to work on web as well.
In the next chapter, let's learn how to handle the differences between mobile and web platforms.
  • Message-iconAsk a question on the forums
  • Edit-iconEdit this page

Was this doc helpful?