In this codelab, you'll interact with the Android sample app to simulate deep linking from Search results on your own Android device. You'll then integrate your app with Google Analytics, using the referrer extra from Search to track different app referrers.

What you'll do

What you'll need

Understanding Deep Link Sources

Before we start, let's take a second to understand the app referral sources this codelab can track.

Clone the repository from GitHub

git clone https://github.com/googlecodelabs/deeplink-referrer.git

...or download the repository as a Zip file

Download Zip

First, let's see what the finished app looks like. Once you've downloaded the code, open the Android sample app in Android Studio:

  1. Select the begin directory from the sample code download. Quickstart > Import Project... > deeplink-referrer
  2. Click the Gradle sync button.
  3. Enable USB debugging on your Android device.
  4. Plug in your Android device and click the Run button.
    The Recipe App home screen should appear after a few seconds.
  5. Enter the following Android Debug Bridge command from a command line terminal:
adb shell am start -a android.intent.action.VIEW \
-d "http://recipe-app.search.samples.google.com/recipe/pierogi-poutine" com.google.samples.search.recipe_app
  1. Verify that a recipe from the app appears on the screen. This is the result of a deep link into the app!

Frequently Asked Questions

Now let's create a Google Analytics property and get a Google Services configuration file to integrate Google Analytics into your app.

  1. Launch the Google Services configuration flow.
  2. Accept the suggested App and package name and click Continue.
  3. In the Google Analytics Account dropdown, create a new account or select an existing one.
  4. In the Analytics Property dropdown, create a new property for your app, or select an existing one.
  5. Click Enable Analytics Service.
  6. Click Continue to Generate configuration files and then click Download google-services.json to download a configuration file that lets your app use the Analytics property you just created.
  7. Place this file in the app directory in your project.
  8. In the begin directory Gradle build file, add a dependency to the Google Services gradle plugin.
    build.gradle
dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
        classpath 'com.google.gms:google-services:1.5.0-beta2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
  1. In the begin/app directory Gradle build file, apply the plugin by adding the following line.
    build.gradle
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 23
    buildToolsVersion "21.1.2"
...

Add the Google Play services Analytics API to the begin/app directory Gradle build file.

build.gradle

dependencies {
    compile 'com.android.support:support-v13:23.0.1'
    compile 'com.google.android.gms:play-services-analytics:8.3.0'
    compile 'com.google.android.gms:play-services-appindexing:8.3.0'
    compile group:'com.squareup.picasso', name:'picasso', version:'2.3.2'
    compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
}

Click the Gradle sync button, then create a new Application subclass in your app to act as a helper class to manage the Analytics configuration data and initialize your Tracker object.

AnalyticsApplication.java

public class AnalyticsApplication extends Application {

    private static final String REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
    private static final String QUICK_SEARCH_BOX = "com.google.android.googlequicksearchbox";
    private static final String APP_CRAWLER = "com.google.appcrawler";

    private static final String REFERRER_PARAM = "utm_source";
    private static final String MEDIUM_PARAM = "utm_medium";

    private static final String NONE = "none";
    private static final String DIRECT = "direct";
    private static final String ORGANIC = "organic";
    private static final String REFERRAL = "referral";

    private Tracker mTracker;


    public synchronized Tracker getDefaultTracker() {
        if (mTracker == null) {
            GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
            // To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
            mTracker = analytics.newTracker(R.xml.global_tracker);
        }
        return mTracker;

    }

   // Added code to track screen view here.
}

Now, it's time to add the decision tree logic that sends different Google Analytics tracking hits depending on the type of view that has occurred. Add the following methods to complete the AnalyticsApplication class.

AnalyticsApplication.java

    public synchronized void trackScreenView(Activity activity, String screenName) {
        Tracker tracker = getDefaultTracker();
        tracker.setScreenName(screenName);

        Uri referrerUri = getReferrer(activity);

        if (referrerUri == null) {
            // App was opened directly by the user
            Log.d(this.getClass().getName(), "Referrer: Direct open");
            tracker.send(new HitBuilders.ScreenViewBuilder()
                    .setCampaignParamsFromUrl(String.format("?%s=%s&%s=%s",
                            MEDIUM_PARAM, NONE, REFERRER_PARAM, DIRECT))
                    .build());
        } else {
            // App was referred via a deep link
            if (referrerUri.getScheme().equals("http") || referrerUri.getScheme().equals("https")) {
                // App was opened from a browser
                String host = referrerUri.getHost();
                if (host.equals("www.google.com")) {
                    Log.d(this.getClass().getName(), "Referrer: Browser (google.com)");
                    tracker.send(new HitBuilders.ScreenViewBuilder()
                            .setCampaignParamsFromUrl(String.format("?%s=%s&%s=%s",
                                    MEDIUM_PARAM, ORGANIC, REFERRER_PARAM, "google.com"))
                            .build());
                } else {
                    Log.d(this.getClass().getName(), "Referrer: Browser (other website)");
                    tracker.send(new HitBuilders.ScreenViewBuilder()
                            .setCampaignParamsFromUrl(String.format("?%s=%s&%s=%s",
                                    MEDIUM_PARAM, REFERRAL, REFERRER_PARAM, host))
                            .build());
                }

            } else if (referrerUri.getScheme().equals("android-app")) {
                // App was opened from another app
                AndroidAppUri appUri = AndroidAppUri.newAndroidAppUri(referrerUri);
                String referrerPackage = appUri.getPackageName();
                if (QUICK_SEARCH_BOX.equals(referrerPackage)) {
                    // App was opened from the Google app
                    Log.d(this.getClass().getName(), "Referrer: Google Search App");
                    tracker.send(new HitBuilders.ScreenViewBuilder()
                            .setCampaignParamsFromUrl(String.format("?%s=%s&%s=%s",
                                    MEDIUM_PARAM, ORGANIC, REFERRER_PARAM, "google_app"))
                            .build());

                } else if (!APP_CRAWLER.equals(referrerPackage)) {
                    // App was deep linked into from another app (excl. Google crawler)
                    Log.d(this.getClass().getName(), "Referrer: Other android app");
                    tracker.send(new HitBuilders.ScreenViewBuilder()
                            .setCampaignParamsFromUrl(String.format("?%s=%s&%s=%s",
                                    MEDIUM_PARAM, REFERRAL, REFERRER_PARAM, referrerPackage))
                            .build());
                }
                // Otherwise, fall through to make sure Google app crawler views
                // are not counted as part of app usage.
            }

        }
    }

    /** Returns the referrer who started the Activity. */
    public Uri getReferrer(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            return activity.getReferrer();
        }
        return getReferrerCompatible(activity);
    }

    /** Returns the referrer on devices running SDK versions lower than 22. */
    private Uri getReferrerCompatible(Activity activity) {
        Intent intent = activity.getIntent();
        Uri referrerUri = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        if (referrerUri != null) {
            return referrerUri;
        }
        String referrer = intent.getStringExtra(REFERRER_NAME);
        if (referrer != null) {
            // Try parsing the referrer URL; if it's invalid, return null
            try {
                return Uri.parse(referrer);
            } catch (ParseException e) {
                return null;
            }
        }
        return null;
    }

In the home screen activity, record an Analytics home screen view.

HomeActivity.java

public class HomeActivity extends Activity {

    private AnalyticsApplication mAnalytics;

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

        mAnalytics = (AnalyticsApplication) getApplication();
    }

    @Override
    protected void onStart() {
        super.onStart();

        // Call the Google Analytics API
        mAnalytics.trackScreenView(this, "Home screen");
    }
}

In the recipe display activity, record an Analytics recipe view based on the title of the recipe displayed.

RecipeActivity.java

private AnalyticsApplication mAnalytics;
...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mAnalytics = (AnalyticsApplication) getApplication();
        ...
    }

    @Override
    public void onStart(){
           ...
            // Define a title for your current page, shown in autocompletion UI
            final String TITLE = recipe.getTitle();
            final Uri APP_URI = BASE_APP_URI.buildUpon().appendPath(recipe.getId()).build();

            // Call the Google Analytics API
            mAnalytics.trackScreenView(this, TITLE);

            ...
    }

Modify AndroidManifest.xml and set the application name to AnalyticsApplication.

AndroidManifest.xml

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:name=".client.AnalyticsApplication"
        android:theme="@style/CustomActionBarTheme" >
...

Now, you're ready to see the hits roll in.

  1. Go to the Google Analytics dashboard.
  2. Click on the Analytics account you created in the Configuring Google Analytics section above.
  3. In the Real-Time section, click on Screens. Your screen views show up here as you interact with your application.
  4. Make sure your Android device is plugged in and click the Run button.
    The Recipe App home screen should appear after a few seconds.
  5. Open a command line terminal on your computer and enter the following Android Debug Bridge command to send a test deep link intent to your app. It uses the -e parameter to simulate referrer information from the Google App.
adb shell am start -a android.intent.action.VIEW \
-d "http://recipe-app.search.samples.google.com/recipe/pierogi-poutine" \
-c android.intent.category.BROWSABLE -e android.intent.extra.REFERRER_NAME android-app://com.google.android.googlequicksearchbox/https/www.google.com com.google.samples.search.recipe_app
  1. After some period of time, you can use other dashboard pages, such as Acquisition > Sources, to see the breakdown of referral sources.

The following decision tree demonstrates how the sample app works to track all the sources of traffic to the app:

Your app is now ready to record referrer data properly in Google Analytics.

What we've covered:

More resources: