Hide

Support Deep Links in your App

The first part to getting your app content in the Google index is ensuring it supports deep links to your content. This guide covers how you do that by adding intent filters and activity logic to respond to deep link intents when users click through to your app from Search results, query autocompletions, and Now on Tap.

Note: Participating in App Indexing currently requires that your app has corresponding content on the web that has also been indexed by Google. If you have an app without corresponding web-page content, and you'd like it discovered by Google Search, fill out our app-only interest form.

Create intent filters

In order for deep links from Google Search results to trigger content views within your app, your app needs intent filters to match HTTP or custom scheme URIs for its content. Create one intent filter for each deep link format that should launch your app content. For example, you'll need two intent filters if your app supports both http://recipe-app.com and recipe-app:// formats.

Example intent filters

The following example demonstrates a URI pattern intended to match HTTP URIs so that the user can open your native app instead of the web page when tapping a link from Search results. Here, users enter the app using an intent to view information about recipes.

This example also shows an intent filter designed to handle custom URI schemes. If you use custom scheme URIs, you can use these data URI formats instead or in addition to HTTP URIs.

<activity
     android:name="com.example.android.RecipeActivity"
     android:label="@string/title_recipe" >
     <intent-filter android:label="@string/filter_title_viewrecipe">
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
         <!-- Accepts URIs that begin with "recipe-app://recipes" -->
         <data android:scheme="recipe-app"
               android:host="recipes" />
     </intent-filter>
     <intent-filter android:label="@string/filter_title_viewrecipes">
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
         <!-- Accepts URIs that begin with "http://recipe-app.com/recipes" -->
         <data android:scheme="http"
               android:host="recipe-app.com"
               android:pathPrefix="/recipes" />
     </intent-filter>
</activity>

The example above allows your app to respond to both HTTP URIs and custom scheme URIs such as the following:

  • http://recipe-app.com/recipes
  • recipe-app://recipes/grilled-potato-salad
  • recipe-app://recipes/desserts/peach-pie

Intent filters for deep links should have these elements:

Tag Description
<action> Specifies the ACTION_VIEW intent action so that the intent filter can be reached from Google Search.
<data>

One for each URI format that the activity accepts. At minimum, the <data> tag must include the android:scheme attribute.

You can add additional attributes to further refine the type of URI that the activity accepts. For example, you might have multiple activities that accept similar URIs, but which differ simply based on the path name. In this case, use the android:path attribute or its variants (pathPattern or pathPrefix) to differentiate which activity the system should open for different URI paths.

<category> Defines both BROWSABLE and DEFAULT intent activities:
  • BROWSABLE: required in order for the intent to be executable from a web browser. Without it, clicking a link in a browser cannot resolve to your app (in which case, only the current mobile web browser will respond to the URL).
  • DEFAULT: necessary only if you want your Android app to respond to an HTTP link from any referring website. The intent used from Google Search results includes the identity of your app, so it explicitly points to your app as the recipient. Other links to your site do not know your app identity, so the DEFAULT category declares your app can respond to an implicit intent.

Verify deep link syntax

Android Studio lint (version 1.3+) automatically flags deep link syntax errors for your intent filters. You can also manually run syntax checking by selecting Analyze > Inspect Code from the application or right-click menu. To turn off deep link checking, disable Missing AppIndexing Support and Wrong usage of Appindexing api from the Android lint inspections panel. See both the lint documentation for Android Studio and Configuring lint in Android.

Deep link syntax warnings appear highlighted in yellow.

Deep link errors are indicated by a red underline.

All errors appear in the bottom window of the editor, for quick access to the line in your manifest.

Add logic to handle deep link intents

Once the system starts the app activity through an intent filter, use the data provided by the Intent to determine your app's view response. Call the getData() and getAction() methods to retrieve the data and action associated with the incoming Intent. You can call these methods at any time during the lifecycle of the activity, but you should generally do so during early callbacks such as onCreate() or onStart().

The following example passes the incoming Intent to a helper method onNewIntent() in onCreate().

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recipes);

    onNewIntent(getIntent());
}

Here, the onNewIntent() method verifies the deep link format and displays the recipe content:

protected void onNewIntent(Intent intent) {
    String action = intent.getAction();
    String data = intent.getDataString();
    if (Intent.ACTION_VIEW.equals(action) && data != null) {
        String recipeId = data.substring(data.lastIndexOf("/") + 1);
        Uri contentUri = RecipeContentProvider.CONTENT_URI.buildUpon()
                .appendPath(recipeId).build();
        showRecipe(contentUri);
    }
}

Restrict access to some content (optional)

In some cases, you might not want Google to index parts of your app. To do this, first include a noindex.xml file in your Android app to indicate which deep links should not be indexed. Then, reference the noindex.xml in the application section of the app’s AndroidManifest.xml file.

Create the noindex.xml file

This file indicates a list of URIs to exclude, or a list of URI prefixes. This is similar to how the robots noindex meta tag works for websites.

Create a new XML file, res/xml/noindex.xml, and put it in your app's XML resources directory. It should look like the following:

<?xml version="1.0" encoding="utf-8"?>
<search-engine xmlns:android="http://schemas.android.com/apk/res/android">
  <noindex uri="http://recipe-app.com/recipes/hidden_uri"/>
  <noindex uriPrefix="http://recipe-app.com/recipes/hidden_prefix"/>
  <noindex uri="recipe-app://hidden_path"/>
  <noindex uriPrefix="recipe-app://hidden_prefix"/>
</search-engine>

Google will not index those deep links that either match the uri attribute exactly or that start with the string matching uriPrefix attribute.

Reference the noindex.xml file

After the noindex.xml file is added, reference it in the application section of the app’s AndroidManifest.xml file. For example:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.Recipes">
  <application>
    <activity android:name="com.example.android.RecipesActivity"
        android:label="@string/title_recipes" >
      <intent-filter android:label="@string/filter_title_viewrecipes">
      <action android:name="android.intent.action.VIEW"/>
      ...
    </activity>
    <meta-data android:name="search-engine" android:resource="@xml/noindex"/>
  </application>
  <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

<meta-data android:name="search-engine" android:resource="@xml/noindex"/> specifies where the noindex.xml file can be found in the app. In order to make sure that your app is indexed consistently, the same noindex.xml file should be included in all versions of your app published in the Google Play Store.

Next, publish your deep links to help Google understand and discover your app content.

Send feedback about...

App Indexing