The following review was conducted by Sampson, Senior Developer Relations Specialist at Brave.

Last year I did a review of several popular desktop browsers, focusing exclusively on what they do when you launch the browser for the first time. Months later, an independent review was conducted by Douglas Leith of Trinity College Dublin. Both investigations found that Brave was, by far, the most private browser among those tested. Today I decided to take a look at various browsers available on iOS 13—specifically, Brave 1.15, DuckDuckGo 7.42.0.1, Mozilla Firefox 24.0, Google Chrome 80.0.3987.95, Opera Touch 2.2.1, and Microsoft Edge 45.2.16. Safari is also briefly examined, but not to the extent of the other browsers, due to certain limitations.

Brave

During its first run, Brave 1.15 on iOS issued 8 requests exclusively to Brave domains. The first request issued was to mobile-data.s3.brave.com/US/photo.json, retrieving information regarding Sponsored Images. The server responded with 524 bytes of JSON containing the current New Tab Page (NTP) sponsor, web addresses for a logo and 3 background images, the sponsor URL, and coordinates for the focal point of each background image.

Brave then proceeds to download JSON and Rust versions of its internal ad-block list from adblock-data.s3.brave.com/iOS13/. The JSON list is used for ad-blocking functionality, whereas the Rust list is used for recording blocking-statistics (displayed on the new tab page). Browsers which don’t intend to present blocking-statistics need only to load a single blocking list.

The final request made by Brave during its first-run is to laptop-updates.brave.com/1/usage/ios for the purpose of anonymously measuring daily and monthly active user numbers. This request carries with it only a few pieces of non-identifying information: channel, version number, the week of installation, and a set of booleans indicating whether this is an initial, daily, weekly, or monthly run.

Once the browser was launched, I typed “brave” into the address bar to see if any keystrokes were unexpectedly being sent out in real-time. This was not the case with Brave; address-bar input does not result in any sort of lookup or auto-complete query. The user is, however, invited to enable such a feature should they choose to do so.

DuckDuckGo

DuckDuckGo (DDG) and Brave align well on security and privacy principles, so it is no surprise that this browser also scores very well on this type of review. On its first launch, DDG issued 13 requests, all of which were to the DDG domain. DDG issues its first request to staticcdn.duckduckgo.com/trackerblocking/v2/tds.json, which loads information used in DDG’s default tracker-blocking behavior. Much of the file contains meta-information (such as user-friendly names and categories) for various known tracker entities.

Next, DDG calls improving.duckduckgo.com/t/m_o_ios_tablet, which appears to collect anonymous usage information, similar to Brave. DDG informs the server that I am on a tablet, and that I am using version 7.42.0.1 of the browser. The server responds with a transparent GIF. This request relates to DDG’s anonymous a/b testing. See Improving DuckDuckGo for more.

DDG’s next calls are related to HTTPS Upgrades, 21 URLs which should temporarily be exempted from tracker-blocking (likely for compatibility), and lastly a set of “surrogates” which can be injected into the context of a page to prevent breakage whilst blocking trackers.

Finally, at the end of this brief survey, I typed “brave” into the address bar to see if keystrokes were sent out. Unlike Brave, DDG does indeed transmit keystrokes as part of its default configuration. Typing “brave” resulted in 5 calls to DDG’s auto-complete service. Each letter inserted resulted in a payload of JSON being downloaded with a set of phrase predictions.

Mozilla Firefox

Firefox generated 14 calls on its first run. Most were to mozilla.net endpoints, but a few were to other domains (e.g. api.leanplum.com, and app.adjust.com). Leanplum, a marketing apparatus, receives a few data points from Firefox, including the appId, version, a timestamp, my timezone, the client platform, a “client key”, and an encoded JSON string of additional “data”.

More should be said of the additional data sent to Leanplum. Firefox shares a deviceId, a userId, and a uuid (universally unique identifier). Firefox also informs Leanplum whether or not I happen to have also installed Firefox Focus, Pocket, and/or Firefox Klar (a telemetry-free build of Firefox Focus for German markets). The JSON also has location, country, city, and region values of “(detect)”, though it is not clear to me what this value means.

When Firefox launches, it displays regional news items beneath the “Trending on Pocket” headline. These items are retrieved from getpocket.cdn.mozilla.net/v3/firefox/global-recs. Firefox sends over the number of items requested, the user’s language and locale, a version (presumably for Pocket), and a consumer key (these are per-app, so all Firefox users on iOS are likely to share this value).

The next item I noticed was a POST to the mobile marketing platform adjust.com. This network call contained quite a bit more information than previous ones. In this call (to a third party, mind you), I can see 28 pieces of information, including a persistent_ios_uuid token. I should mention that there is a tracking_enbled entry too, which has a value of 0. The server responds with a small payload of JSON data, which includes an adid (ad ID?). Moments later another call is made to adjust.com with my persistent_ios_uuid and more; the response confirms that these calls are for tracking attribution.

The last step in this review was to type “brave” into the address bar, and see if Firefox, out of the box, would send my keystrokes off to a remote party. In fact, it does. However, unlike DDG (which sends keystrokes to duckduckgo.com), Firefox sends keystrokes directly to google.com, passing along “firefox” as the client for attribution.

Google Chrome

Chrome issued 35 requests when it first launched—that’s as many Brave, DuckDuckGo, and Mozilla Firefox combined. While most endpoints belonged to Google, many did not. Chrome first calls out to update.googleapis.com/service/update2 to check that the browser is up to date. In addition to the browser version and my device platform, the XML payload also contains a userid.

Next, Chrome requests a JSON payload of suggested sites for American audiences. This data comes from gstatic.com/chrome/ntp/suggested_sites_US_5.json. The response contains URLs for icons, which Chrome then proceeds to download from each of the respective domains. For the most part, these image requests don’t appear to result in many cookies. Wikipedia does set a cookie, and includes within it my Country, State, City, and Coordinates. This cookie persists in future user-navigations as well.

Similar to Chrome on desktop, clientservices.googleapis.com/chrome-variations/seed is pinged to retrieve Field Trials for this particular browser instance. Like Firefox, Chrome displays news on its new tab page. chromefeedcontentsuggestions-pa.googleapis.com/v2/suggestions/fetch is responsible for serving this data to the browser instance. It’s worth noting that in other browsers, this type of data typically comes with an image to display as well. That isn’t the case with Chrome. Instead, the URL of the site is passed to a Google Service, and an image is returned for displaying. This prevents your browser instance from reaching out to third-party domains.

At the end of this brief walk through Chrome’s network activity, I continued my tradition of typing “brave” into the address bar to see what, if anything, would happen. Unsurprisingly, Chrome calls to the same endpoint as Firefox, noting the client is chrome.

Opera Touch

Opera issued 17 calls during its first launch, however to my surprise all of them were to third-party domains. Opera issued no requests to domains within the control of Opera Software.

The first request made was to device-provisioning.googleapis.com/checkin, and contains a small payload of JSON data communicating information about my device and location. Among the data are my device-type (iPad 11,1), os-version (IOS_13.3.1), and my timezone. There are other values too, such as user_number, id, and user_serial_number, which all have a value of 0.

Moments later Opera issues a call to fcmtoken.googleapis.com/register, which begins the process of associating my device with the Firebase Cloud Messaging service. This service enables Opera to transmit messages to a specific device or a group of devices. As such, we should expect to see some type of unique ID generated, and we do. In the request data, I see a 19-digit device number. Presumably this is used for Firebase message transmission.

Next up, Opera calls out to firebasedynamiclinks-ipv4.googleapis.com/v1/installAttribution and firebasedynamiclinks-ipv6.googleapis.com/v1/installAttribution (ipv4 vs ipv6). Each call carries along with it a shared key. I suspect this is for referrals, though because I downloaded organically, the server response is “No pre-install link matched for this device.”

Opera also makes a few calls to t.appsflyer.com, attr.appsflyer.com, and sdk.appsflyer.com. AppsFlyer, like Firebase in part, handles Deep Linking and Mobile Attribution. The payloads to t.appsflyer.com and attr.appsflyer.com are not easily dissected, so it isn’t clear what data is being sent to those endpoints. The only thing we can tell from the logs is that an app ID is sent, along with a build number. In both cases, the server responds with a simple “ok”.

At the end of this review, I typed “brave” into the address bar to find that each letter triggered a call to clients1.google.com/complete/search, with the client being identified as Opera Mobile.

Microsoft Edge

Microsoft Edge was, considerably, the most active browser immediately into its first run, prior to any user navigation. Edge issued no fewer than 115 requests to 27 distinct domains. Several of the requests were to Microsoft-controlled endpoints, such as msn.com, bing.com, microsoft.com, windows.net, and msedge.net. That said, many requests were made to other endpoints like taboola.com, zemanta.com, bttrack.com, creativecdn.com, liadm.com, akamaized.net, scorecardresearch.com, braze.com (not to be confused with brave.com), doubleclick.net, ml314.com, bluekai.com, and more.

Beyond the array of endpoints contacted, the data being sent around also drew my attention. In the first request Edge makes (to settings.data.microsoft.com), I see a 32-bit deviceId. Out of curiosity I deleted Edge, re-installed, and found that an identical ID was generated again. This token is immediately sent to onesettings-windowsservices-tas.msedge.net as a “clientid”. The token is shared with other Microsoft domains, which isn’t very surprising. I was, however, fairly surprised to find that this token was shared with non-Microsoft endpoints too (e.g. app.adjust.com, sdk.iad-01.braze.com).

As is the case on desktop, Edge for iOS loads its new tab page from www.msn.com. Specifically, it loads msn.com/spartan/mmx?locale=en-us&rt=1 in my case. This page then proceeds to connect with numerous third-parties, centered largely around Real-Time Bidding, and auctioning ad-space (and the user’s attention) off to various advertisers.

Edge makes regular calls to c.msn.com/c.gif; these requests contain information about the page being accessed, my resolution, language, and more. They also contain timestamps, an activity ID, and a MUID cookie. The server responds by informing the browser to redirect the same information to c.bing.com, pass this data on to another host. A cursory scan of the traffic reveals my MUID cookie value is also sent to third parties like api.taboola.com, ml314.com, and pxl.connexity.net. Note, these are the advertisers who (presumably) won the auction for my attention. As such, this information is likely to be shared with far more entities.

While Edge for iOS ships with AdBlock Plus, the extension is off by default and must be enabled by the user. Upon enabling, the user is informed that they will still see “acceptable ads”. After enabling, I restarted Edge to see if the connections would look any different—they weren’t. I still noticed several calls to sites like doubleclick.net, taboola.com, and more. I would have expected AdBlock Plus to prevent these calls, since they’re third-parties, and known trackers.

Edge, like many of the browsers we’ve examined today, also emits pings for each keystroke in the address bar. As I typed “brave”, c.bingapis.com/api/custom/opal/suggestions/web began to fill my network logs; one entry for each letter added to the search term. It’s worth noting the 32-bit deviceId I mentioned at the start is sent with each call to c.bingapis.com as a custom request header.

Apple Safari

No list of popular iOS browsers would be complete if it didn’t include Safari. Unfortunately, given the nature of Safari’s relationship with iOS, it’s not easy for me to remove and reinstall the browser for testing purposes. At best, I appear to have only the ability to remove browsing history and data, but that isn’t sufficient for the purposes of this review.

One thing we can observe is what Safari does with keystrokes. Like every browser reviewed (with the exception of Brave), keystrokes are automatically sent to a remote server. While DDG sends them to their own service endpoint, Safari joins the rest of the browsers in sending user keystrokes directly to Google.

On as fresh an instance as I could create, I typed “brave” into my iPad and recorded the network activity. clients1.google.com/complete/search was queried once per letter-added, with the client being recorded as “iphonesafari”.

Apple also sent some keystrokes to their own endpoint at api-glb-atl.smoot.apple.com/search, with quite a few more data points. This endpoint appears to make app suggestions. The data sent includes my country, language, type of connection, keyboard layout and language, coordinates, timezone, and query (“brave”, in this case).

Conclusions