This is a paid beta feature that only certain customers can access. If you are not part of the beta program and you would like try it as well, then contact us through support.
Latest release: 0.0.6
The billypix
sdk takes care of in native Android in app tracking for your Billy Grace account. Do please take a good look at the implementations details as this does need to be setup correctly for it to fully work with work AI Marketing Optimisation Software.
Introduction to In-App Tracking
In-app tracking in Billy Grace allows to measure conversions that happen inside your app and link them back to the marketing efforts that drove users there.
What’s possible?
Track in-app conversions that result directly from marketing campaigns.
Attribute those conversions to the specific marketing channel or campaign that contained a direct call-to-action button opening the app, provided the app is already installed on the user’s device when they click the ad or link.
What’s not possible?
Measuring app installs.
Stitching together web and app user journeys.
Attributing conversions that happen after an App Store redirect (for example, when the app needs to be installed before being opened). In these cases, the UTM parameters are lost. On iOS this happens consistently, on Android it depends on the setup.
Scenario 1
App install
Youtube view > Meta click > Google click > App interaction > Conversion
In this scenario, we are able to attribute the conversion value to Youtube, Meta & Google
Scenario 2
App not yet installed
Youtube view > Meta click > Google click > App Interaction (install) > Conversion
In this scenario, we are not able to attribute any value to Youtube, Meta or Google. However, we are able to measure the conversion.
Why it’s valuable?
Adding in-app conversions to your tracking gives you a more complete picture of your marketing performance. Instead of seeing only web-based conversions, you’ll also understand the impact of campaigns driving users directly into your app. This helps you:
Accurately measure all your online conversions: web and app combined.
See which marketing channels work best for each platform, so you can optimise campaigns specifically for app traffic or web traffic.
Reduce unattributed conversions, making ROI calculations more reliable.
Spot opportunities where app experiences lead to higher conversion rates or better customer retention.
How will you see this data in Billy Grace?
Currently, all your web and app data is combined in one view. While you cannot yet separate the two, this helps reduce the number of unattributed orders or conversions.
In the future, we will include web and app in our filtered views, allowing you to distinguish between app and web conversions, as well as the journeys leading to them.
Installation
Step 1) Adding our repository url
To get our Android library up and running you will first need to add our repository url to your settings.gradle
:
maven {
url = uri("https://android.cdn.billypx.com/")
}
Below you see an example for settings.gradle.kts
:
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://android.cdn.billypx.com/")
}
}
}
rootProject.name = "Example App"
include(":app")
Step 2) Add the library
Now that the app can connect to our repository for installation, you can add our library to your gradle file. You will need to specify which version you will install explicitly. For example:
// Billypix Android
implementation("com.billygrace:bg_pix_android:0.0.6")
Sync it and you can start using our library.
Configuration
First make sure to copy over your own tracking id from the pixel page in the web application. It should like something like: ID-12-34567, you will need this when implementing our library.
IMPORTANT: you need to determine how you want to track the pageloads/pageviews. You will need to set the option when initializing the sdk using the PageloadTrackingType
enum.
There are the options:
PageloadTrackingType.COMPOSE
-> Automaticpageload
tracking: Composable viewsPageloadTrackingType.ACTIVITY_OR_FRAGMENT
-> Automaticpageload
tracking: Activity or FragmentsPageloadTrackingType.NONE
-> Manualpageload
tracking: Implement thepageload
event yourself manually on each page in the app
Below you can find the instructions for each way of tracking:
Option A) Automatic pageload
tracking: Composable views
Then the initialization code at the first thing when your app opens. This needs to be called in your first/main Activity
.
First make sure to set pageloadTrackingType
to PageloadTrackingType.COMPOSE
on initialization, which will take care of tracking each pageload:
import com.billygrace.billypix.BillyLogLevel
import com.billygrace.billypix.BillyPix
import com.billygrace.billypix.PageloadTrackingType
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
// Initialize BillyPix
BillyPix.configure(
context = this,
trackingId = "ID-XX-XXXXX",
pageloadTracking = PageloadTrackingType.COMPOSE,
)
..............................
Then to get compose based view tracking to work, you will need to pass in your NavHostController to the library once you initialize it. So for example:
@Composable
fun CupcakeApp(
viewModel: OrderViewModel = viewModel(),
navController: NavHostController = rememberNavController()
) {
// Set up Compose navigation tracking
BillyPix.setUpComposeTracking(navController)
..............................
Option B) Automatic pageload
tracking: Activity or Fragments
Then the initialization code at the first thing when your app opens need to be called. You can do this in the Application
class or in your first Activity
. Make sure to set pageloadTrackingType
to PageloadTrackingType.ACTIVITY_OR_FRAGMENT
on initialization, which will take care of tracking each pageload:
import com.billygrace.billypix.BillyLogLevel
import com.billygrace.billypix.BillyPix
import com.billygrace.billypix.PageloadTrackingType
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
// Initialize BillyPix
BillyPix.configure(
context = this,
trackingId = "ID-XX-XXXXX",
pageloadTracking = PageloadTrackingType.ACTIVITY_OR_FRAGMENT,
)
..............................
Option C) Manual pageload
tracking
If you want to have full control and implement each pageload manually, you have to call the BillyPix.send()
function for each Activity, Fragment or Composable view.
First initialize the library at the start of your application like this:
import com.billygrace.billypix.BillyLogLevel
import com.billygrace.billypix.BillyPix
import com.billygrace.billypix.PageloadTrackingType
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
// Initialize BillyPix
BillyPix.configure(
context = this,
trackingId = "ID-XX-XXXXX",
pageloadTracking = PageloadTrackingType.NONE,
)
..............................
Then you can start to track the pageload events manually, make sure to also pass in the page_name
and class_name
, so pages/view can be differentiated between in Billy Grace.
import com.billygrace.billypix.BgEventKey
import com.billygrace.billypix.BgEventName
........
// Used to differentiate between pages/screens in Billy Grace
val pageName = "mainPage"
val className = "ComposableSecondPage"
// Send the 'pageload' event manually on each screen
BillyPix.sendEvent(BgEventName.PAGELOAD, mapOf(
BgEventKey.PAGE_NAME to pageName,
BgEventKey.CLASS_NAME to className
))
Other configuration options
You have multiple configuration options, you can use like for example:
countryCode
Billy grace accounts are generally scoped to 1 country while an App is mostly deployed to multiple countries. So to help differentiate between which account and country that the traffic needs to be routed to, we want to include the countryCode.
If you do not set this, then the SDK grab the internal Locale's country (so which region the user has set in their android settings)
If you want to control this setting yourself, then we highly recommend you set this yourself, as it will overwrite the default we use. You set this once on BillyPix.configure()
, and will then be included into each event being send for that user.
BillyPix.configure(
context = this,
trackingId = "ID-XX-XXXXX",
countryCode = "NL", // Add this
pageloadTracking = PageloadTrackingType.COMPOSE
)
billyLogLevel
This determines from which level and up you want to see logs for, the default for this is INFO
. The hierarchy for the log levels works like this:
VERBOSE
DEBUG
INFO
WARN
ERROR
NONE
So for example the following code with BillyLogLevel.DEBUG
:
BillyPix.configure(
context = this,
trackingId = "ID-XX-XXXXX",
pageloadTracking = PageloadTrackingType.COMPOSE,
billyLogLevel= BillyLogLevel.DEBUG
)
Will output all the log levels from INFO and up which are: INFO, WARN and ERROR.
Attribution in app
We highly recommend you take this step as well, as we can’t run any attribution algorithms as the url the app was opened with contains the url parameters needed for attribution.
This can be done in 2 ways:
Directly passing down the
intent
objectOr if you are using a library, that can retrieve the parameters from the original deeplink that initially triggered opening the app, you can pass them down directly to the sdk.
1) Passing parameters through the intent
object
In the class where you open your intent add the following line of code so the tracking library can parse the url parameters:
// Grab the url (if any) that the app was opened with
intent.data?.let {
BillyPix.handleURLOpen(it.toString(), type = "intent")
}
2) Passing parameters manually
Here is an example on how to pass url that triggered opening the app to the sdk:
import com.billygrace.billypix.BillyPix
// If you have a URL:
val deferredLinkUrl = "https://yourapp.com/path?utm_source=email&utm_campaign=welcome"
BillyPix.handleURLOpen(deferredLinkUrl, type = "deeplink")
Tracking events
We recommend that you send us the following events (if applicable):
BgEventName.PAGELOAD
BgEventName.ADD_TO_CART
BgEventName.PURCHASE_STARTED
BgEventName.PURCHASE
Other events
Tracking any other event is pretty straightforward. Do make sure to import the sdk and BgEventName
and BgEventkey
accordingly:
import com.billygrace.billypix.BillyPix
import com.billygrace.billypix.BgEventKey
import com.billygrace.billypix.BgEventName
You can define the name of event as a string or you can use the build in event name identifiers with BgEventName
for common events (recommended).
For example using the build in event name identifiers:
BillyPix.sendEvent(BgEventName.PURCHASE_STARTED, mapOf(
BgEventKey.TRANSACTION_ID to "133hh",
))
Send an event we don’t have an identifier for (so as string):
BillyPix.sendEvent("custom_event_name", mapOf(
BgEventKey.TRANSACTION_ID to "133hh",
))
The keys of the parameters for each event also have a list of predefined options we recommend you use, you can us the BgEventKey
object for this. Furthermore, in this case you can also still define parameter keys as strings.
For example, this works as well:
BillyPix.sendEvent(BgEventName.PURCHASE_STARTED, mapOf(
BgEventKey.TRANSACTION_ID to "133hh",
"some_custom_key" to "123"
))
Below are a few examples:
Event: Purchase
import com.billygrace.billypix.BillyPix
.....
BillyPix.sendEvent(BgEventName.PURCHASE, mapOf(
BgEventKey.VALUE to "57",
BgEventKey.TRANSACTION_ID to "xe3x")
)
Event: Form submission
import com.billygrace.billypix.BillyPix
.....
BillyPix.sendEvent("form_submitted")