Network tracking and interception SDK support
Network tracking and interception is supported in Android SDK version 2.2.2 and up. For information on updating your SDK, see Android integration.
Tracking network requests
To manually track network requests:
val networkRequest = SmartlookNetworkRequest(
duration = 1000,
url = URL("https://www.example.com"),
method = "POST",
protocol = "http/1.1",
initiator = "OkHttp",
status = SmartlookNetworkRequest.Status.OK,
statusCode = 200,
cached = false,
requestBody = "{\"example\":\"body\"}",
responseBody = "{\"example\":\"body\"}",
requestHeaders = mutableMapOf("sample" to mutableListOf("header")),
responseHeaders = mutableMapOf()
)
Smartlook.instance.trackNetworkRequest(networkRequest)
SmartlookNetworkRequest networkRequest = new SmartlookNetworkRequest(
1000,
new URL("https://www.example.com"),
"POST",
"http/1.1",
"OkHttp",
SmartlookNetworkRequest.Status.OK,
200,
false,
"{\"example\":\"body\"}",
"{\"example\":\"body\"}",
new HashMap<String, List<String>>() {{
put("sample", new ArrayList<String>() {{
add("header");
}});
}},
new HashMap<>()
);
Smartlook.getInstance().trackNetworkRequest(networkRequest);
Network request parameters
Network request parameters | Description |
---|---|
start | Unix timestamp marking the start of request |
duration | Duration of the request |
url | Request url |
method | HTTP method |
protocol | Protocol used to execute the request (e.g. "http/1.1") |
initiator | The technology/framework used to execute the request (e.g. "OkHttp") |
status | Request was successful or failed |
statusCode | HTTP status code |
cached = TRUE | Shown if the response body was obtained from cache |
requestBody | String representation of the request body. Maximum allowed number of characters is 10000 (every character beyond this limit is dropped) |
responseBody | String representation of response body. Maximum allowed number of characters is 10000 (every character beyond this limit is dropped) |
requestHeaders | Map of request headers |
responseHeaders | Map of response headers |
Network interceptor
A network interceptor lets you monitor and track REST requests as they flow between a client application and a server.
The Smartlook SDK for Android currently provides a network interceptor for OkHttp.
OkHttp network interceptor
Installation
SmartlookOkHttpInterceptor
is distributed as a separate package and needs to be included alongside smartlook-analytics
.
Your module Gradle file:
// smartlook-analytics dependency
implementation 'com.smartlook.android:smartlook-analytics:<<current-android-2-0-sdk-version>>'
//smartlook-analytics-okhttp dependency
implementation 'com.smartlook.android:smartlook-analytics-okhttp:<<current-android-2-0-sdk-version>>'
Android SDK integration
If you don't have the
smartlook-analytics
dependency included in your module Gradle file, see Android integration.
Default network interception
Interceptors can be used without any configuration using SmartlookOkHttpInterceptor
:
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(SmartlookOkHttpInterceptor())
.build()
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new SmartlookOkHttpInterceptor());
OkHttpClient client = builder.build();
What data is captured
Due to Smartlook Privacy by design, not all data is captured. The SmartlookOkHttpInterceptor
captures data that is intercepted by default.
The following data is captured by default:
- All basic data:
start
,duration
,url
,method
,protocol
,initiator
,status
,statusCode
,cached
The following headers are considered safe:
A-IM
,Accept
,Accept-Charset
,Accept-Datetime
,Accept-Encoding
,Accept-Language
,Access-Control-Request-Method
,Access-Control-Request-Headers
,Cache-Control
,Connection
,Content-Encoding
,Content-Length
,Content-MD5
,Content-Type
,Cookie
,Date
,Expect
,Forwarded
,From
,Host
,HTTP2-Settings
,If-Match
,If-Modified-Since
,If-None-Match
,If-Range
,If-Unmodified-Since
,Max-Forwards
,Origin
,Pragma
,Prefer
,Range
,Referrer
,TE
,Trailer
,Transfer-Encoding
,User-Agent
,Upgrade
,Via
,Warning
The following data isn't captured:
requestBody
andresponseBody
because they can contain sensitive data
Non-binary body interceptor
SmartlookNonBinaryBodyInterceptor
replaces requestBody
and responseBody
with String
representations of the original bodies if the content-type
is one of the following:
text/plain
text/csv
application/xml
,text/xml
,application/json
,application/ld+json
,text/x-markdown
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(SmartlookNonBinaryBodyInterceptor())
.build()
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new SmartlookNonBinaryBodyInterceptor());
OkHttpClient client = builder.build();
Headers interceptor
You can decide which headers to capture with SmartlookHeadersInterceptor
:
val masks = setOf("Example-Header", "Accept.*")
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(SmartlookHeadersInterceptor(masks))
.build()
Set<String> masks = Set.of("Example-Header", "Accept.*");
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new SmartlookHeadersInterceptor(masks));
OkHttpClient client = builder.build();
As you can see in the example, SmartlookHeadersInterceptor
lets you define set
of allowed header names. Regular expressions can be used too, meaning that headers like Accept-Charset
, Accept-Encoding
, and Accept-Language
can be captured.
Mask URL interceptor
You can filter sensitive parts of URLs with SmartlookMaskUrlInterceptor
:
val masks = setOf(
SmartlookMaskUrlInterceptor.Mask(
regexPattern = "(secret=)[^&]+(&*)",
replaceWith = "$1<hidden>$2"
)
)
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(SmartlookMaskUrlInterceptor(masks))
.build()
Set<SmartlookMaskUrlInterceptor.Mask> masks = Set.of(
new SmartlookMaskUrlInterceptor.Mask(
"(secret=)[^&]+(&*)",
"$1<hidden>$2"
)
);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new SmartlookMaskUrlInterceptor(masks));
OkHttpClient client = builder.build();
SmartlookMaskUrlInterceptor.Mask
has two parameters:
regexPattern
/regex
—Regular expression used to define parts of URL that should be masked. It can be defined as aString
pattern orRegex
.replaceWith
—AString
used to mask/replace matched URL part.
An example URL with masking using the code example:
// URL before masking
https://www.example.com/sample?secret=token&test=param
// URL after masking
https://www.example.com/sample?secret=<hidden>&test=param
Mask body interceptor
You can mask sensitive parts of the request and response bodies using SmartlookMaskBodyInterceptor
:
val masks = setOf(
SmartlookMaskBodyInterceptor.Mask(
"\"sensitive\"[:]\\s(\".*\")",
"sensitive: <hidden>"
)
)
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(SmartlookMaskBodyInterceptor(masks))
.build()
Set<SmartlookMaskBodyInterceptor.Mask> masks = Set.of(
new SmartlookMaskBodyInterceptor.Mask(
"\"sensitive\"[:]\\s(\".*\")",
"sensitive: <hidden>"
)
);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new SmartlookMaskBodyInterceptor(masks));
OkHttpClient client = builder.build();
SmartlookMaskBodyInterceptor.Mask
has two parameters:
regexPattern
/regex
—Regular expression used to define parts of the body that should be masked. It can be defined as aString
pattern orRegex
.replaceWith
—AString
used to mask/replace matched body parts.
An example body with masking using the code example:
// Body before masking
{
"sample": "json",
"sensitive": "password"
}
// Body after masking
{
"sample": "json",
"sensitive": <hidden>
}
Custom network interceptor
If none of the above interceptors suit your needs, you can define a custom interceptor:
class CustomInterceptor: SmartlookOkHttpInterceptor() {
override fun onIntercept(
original: SmartlookChain,
intercepted: SmartlookNetworkRequest
): SmartlookNetworkRequest? {
// Process original and modify intercepted
return intercepted
}
}
public static class CustomInterceptor extends SmartlookOkHttpInterceptor {
@Override
public SmartlookNetworkRequest onIntercept(
@NonNull SmartlookChain original,
@NonNull SmartlookNetworkRequest intercepted
) {
// Process original and modify intercepted
return intercepted;
}
}
The onIntercept
function has the following parameters:
original
—Contains all request data:chain
—Standard OkHttp intercepted request stored inInterceptor.Chain
. Because the Smartlook SDK already processed this chain, do not call theproceed()
function. If you want to read the response, use the second parameterprocessedResponse
.processedResponse
—Response data stored in standard OkHttpResponse
.
intercepted
—Contains previously intercepted data. If this is the first interceptor, it contains data that is intercepted by default.
The return type is SmartlookNetworkRequest?
if you return:
null
—This request will not be tracked.SmartlookNetworkRequest
—Instance with data that you want to track that the request will be tracked.
Interceptor chaining
Multiple interceptors can be used to process the intercepted request:
val client = OkHttpClient.Builder()
.addSmartlookInterceptor(InterceptorA())
.addSmartlookInterceptor(InterceptorB())
.addSmartlookInterceptor(InterceptorC())
.build()
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpExtKt.addSmartlookInterceptor(builder, new InterceptorA());
OkHttpExtKt.addSmartlookInterceptor(builder, new InterceptorB());
OkHttpExtKt.addSmartlookInterceptor(builder, new InterceptorC());
OkHttpClient client = builder.build();
Interceptor order
When there are multiple interceptors, interceptors are used in the order they are entered. In the above example,
InterceptorA
is the first andInterceptorC
is the last.