Track web browser usage in Android using Accessibility Service

Accessibility Service, although meant to assist users with disabilities, is a powerful tool to track user behaviour. It gives us the ability to track user gestures, monitor app usage and also read text from various apps among other things.

We can track the urls visited by a user by implementing an Accessibility Service listener in the following way. It starts by defining our service in AndroidManifest.xml file in the following way.

<service android:name=".LogUrlService"
<action android:name="android.accessibilityservice.AccessibilityService" />
<meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" />


Details on what kind of events we want to listen will go in an xml file named accessibilityservice .Here are the contents of that file. The event we are interested in are typeWindowsChanged ,typeWindowStateChanged & typeWindowContentChanged. Another important property is canRetrieveWindowContent which is set to true.

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android=""
android:accessibilityEventTypes = "typeWindowsChanged|typeWindowStateChanged|typeWindowContentChanged"



Permission to access this service needs to be explicitly granted to your app by the user, by navigating to Settings->Apps&Notifications>Advanced>Special App usage>Accessibility or we can do this programatically by calling the accessibility settings intent

Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);

Once permission has been granted, our service starts receiving callbacks whenever the accessibility events are trigerred. Since this event will be triggered by all apps, we need to filter it to ensure that we are only processing events related to a web browser. We need to know beforehand the package name of the browser we are going to track. Every time an event is triggered, we are presented with an AccessibilityNodeInfo object, which includes the window content as well as a tree of the child AccessibilityNodeInfo of this parent object. We look for a particular node , which represents the addressbar of that browser. This is unique for every browser. This is a one time activity which we get by traversing through the nodes and figuring out which node contains the data and get the associated node id name.

private void getChild(AccessibilityNodeInfo info)
int i=info.getChildCount();
for(int p=0;p<i;p++)
AccessibilityNodeInfo n=info.getChild(p);
if(n!=null) {
String strres = n.getViewIdResourceName();
if (n.getText() != null) {
String txt = n.getText().toString();
Log.d("Track", strres + " : " + txt);

Once this is done , we can build a list with the package names and the unique node id name. Here is a list with a few popular browsers on android

private static List<SupportedBrowserConfig> getSupportedBrowsers() {
List<SupportedBrowserConfig> browsers = new ArrayList<>();

browsers.add( new SupportedBrowserConfig("", ""));

browsers.add( new SupportedBrowserConfig("org.mozilla.firefox", "org.mozilla.firefox:id/mozac_browser_toolbar_url_view"));

browsers.add( new SupportedBrowserConfig("com.opera.browser", "com.opera.browser:id/url_field"));

browsers.add( new SupportedBrowserConfig("", ""));

browsers.add( new SupportedBrowserConfig("", ""));

browsers.add( new SupportedBrowserConfig("", ""));

return browsers;

Now all that is left is to query for the content of that particular node whenever the browser window becomes active or changes.

case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:

case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
AccessibilityNodeInfo parentNodeInfo = event.getSource();
if (parentNodeInfo == null) {

String packageName = event.getPackageName().toString();
SupportedBrowserConfig browserConfig = null;
for (SupportedBrowserConfig supportedConfig: getSupportedBrowsers()) {
if (supportedConfig.packageName.equals(packageName)) {
browserConfig = supportedConfig;
if (browserConfig == null) {

String capturedUrl = captureUrl(parentNodeInfo, browserConfig);

if (capturedUrl == null) {

Now we can continuously monitor in the background all the urls visited by a user even if the browser is operated in incognito mode.

You can find the source files of this project here

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

The Middle Aged Programmer

Written by

You guessed it, i am a middle aged programmer who has been writing code for the last 20+ years. Current platforms include C, Java, PHP and nodejs.

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store