Usage examples
- Library initialization with the extended configuration
- Sending statistics to an additional API key
- Tracking app crashes
- Determining the location
- Setting device location manually
- Sending a custom event
- Sending a custom event with nested parameters
- Sending an event from the WebView's JavaScript code
- Sending an error message
- Sending ProfileId
- Sending profile attributes
- Sending E-commerce events
- Sending Revenue
- Sending Ad Revenue data
- Setting the session timeout
- Setting the app version
- Tracking app opens using deeplinks
- Tracking new users
- Disabling and enabling sending statistics
- Getting AppMetrica SDK IDs
Library initialization with the extended configuration
To initialize the library with the extended startup configuration:
- Initialize an instance of the
AppMetricaConfiguration
class. - Specify the configuration settings using methods of the
AppMetricaConfiguration
class. For example, enable logging or set a session timeout. - Pass the
AppMetricaConfiguration
instance to theactivate(with:)
method of theAppMetrica
class.
The parameters of the extended configuration are applied from the time of library initialization. To configure the library while the app is running, use the AppMetrica
class methods.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : AnyObject]? = nil) -> Bool {
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Setting up the configuration. For example, to enable logging.
configuration.areLogsEnabled = true
// ...
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
}
- Initialize an instance of the
AMAAppMetricaConfiguration
class. - Specify the configuration settings using methods of the
AMAAppMetricaConfiguration
class. For example, enable logging or set a session timeout. - Pass the
AMAAppMetricaConfiguration
instance to the+activateWithConfiguration:
method of theAMAAppMetrica
class.
The parameters of the extended configuration are applied from the time of library initialization. To configure the library while the app is running, use the AMAAppMetrica
class methods.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Setting up the configuration. For example, to enable logging.
configuration.logsEnabled = YES;
// ...
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
return YES;
}
What is an API key?
The API key is a unique app ID issued in the AppMetrica web interface at app registration. You can find it under Settings.
Sending statistics to an additional API key
Sending data to an additional API key allows you to collect own statistics for these API keys. You can use this to control access to information for other users. For example, to provide access to statistics for analysts you can duplicate sending marketing data for the additional API key. Thus they will only have access to the information they need.
To send data to an additional API key, you must use reporters. Just like for the main API key, you can set up an extended startup configuration for a reporter, send events, profile information, and data about in-app purchases. The reporter can work without the AppMetrica SDK initialization.
Step 1. (Optional) Initialize a reporter with an extended configuration
Warning
The reporter with the extended configuration should be initialized before the first call to the reporter. Otherwise, the reporter will be initialized without a configuration.
To initialize a reporter with an extended configuration:
- Initialize an instance of the
MutableReporterConfiguration
class. - Specify the configuration settings using methods of the
MutableReporterConfiguration
class. For example, enable logging or set a session timeout. - Pass the
MutableReporterConfiguration
instance to theactivateReporter(with:)
method of theAppMetrica
class. - This configuration is used for a reporter with the specified API key. You can set up your own configuration for each additional API key.
// Creating an extended library configuration.
// To create it, pass an API key that is different from the app's API key.
if let reporterConfiguration = MutableReporterConfiguration(apiKey: "API key") {
// Setting up the configuration. For example, to enable logging.
reporterConfiguration.areLogsEnabled = true
// ...
// Initializing a reporter.
AppMetrica.activateReporter(with: reporterConfiguration)
}
- Initialize an instance of the
AMAMutableReporterConfiguration
class. - Specify the configuration settings using methods of the
AMAMutableReporterConfiguration
class. For example, enable logging or set a session timeout. - Pass the
AMAMutableReporterConfiguration
instance to the+activateReporterWithConfiguration:
method of theAMAAppMetrica
class. - This configuration is used for a reporter with the specified API key. You can set up your own configuration for each additional API key.
// Creating an extended library configuration.
// To create it, pass an API key that is different from the app's API key.
AMAMutableReporterConfiguration *reporterConfiguration = [[AMAMutableReporterConfiguration alloc] initWithAPIKey:@"API key"];
// Setting up the configuration. For example, to enable logging.
reporterConfiguration.logsEnabled = YES;
// ...
// Initializing a reporter.
[AMAAppMetrica activateReporterWithConfiguration:[reporterConfiguration copy]];
What is an API key?
The API key is a unique app ID issued in the AppMetrica web interface at app registration. You can find it under Settings.
Step 2. Configure sending data using a reporter
To send statistics data to another API key:
-
Use the
reporter(for:)
method of theAppMetrica
class to get the instance that implements theAppMetricaReporting
protocol.If the reporter was not initialized with the extended configuration, calling this method will initialize the reporter for the specified API key.
-
Use methods of the
AppMetricaReporting
protocol to send events and revenue. -
To ensure that sessions are tracked correctly, set up sending session start and pause events for each reporter.
guard let reporter = AppMetrica.reporter(for: "API key") else {
print("REPORT ERROR: Failed to create AppMetrica reporter")
return // or return someDefaultValue or throw someError
}
reporter.resumeSession()
// ...
reporter.reportEvent(name: "Updates installed", onFailure: { (error) in
print("REPORT ERROR: %@", error.localizedDescription)
})
// ...
reporter.pauseSession()
-
Use the
+reporterForAPIKey:
method of theAMAAppMetrica
class to get the instance that implements theAMAAppMetricaReporting
protocol.If the reporter was not initialized with the extended configuration, calling this method will initialize the reporter for the specified API key.
-
Use methods of the
AMAAppMetricaReporting
protocol to send events and revenue. -
To ensure that sessions are tracked correctly, set up sending session start and pause events for each reporter.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"API key"];
[reporter resumeSession];
// ...
[reporter reportEvent:@"Updates installed" onFailure:^(NSError *error) {
NSLog(@"REPORT ERROR: %@", [error localizedDescription]);
}];
// ...
[reporter pauseSession];
What is an API key?
The API key is a unique app ID issued in the AppMetrica web interface at app registration. You can find it under Settings.
Tracking app crashes
Reports on app crashes are sent by default.
To disable automatic tracking, pass the configuration in which sending crashes is disabled to the crash module.
To do this, set the false
value for the autoCrashTracking
property of the AppMetricaCrashesConfiguration
configuration.
// Creating a crashes configuration.
let configuration = AppMetricaCrashesConfiguration()
// Disabling sending the information on crashes of the application.
configuration.autoCrashTracking = false
// Set the configuration for AppMetricaCrashes.
AppMetricaCrashes.crashes().setConfiguration(configuration)
To do this, set the NO
value for the autoCrashTracking
property of the AMAAppMetricaCrashesConfiguration
configuration.
// Creating a crashes configuration.
AMAAppMetricaCrashesConfiguration *configuration = [[AMAAppMetricaCrashesConfiguration alloc] init];
// Disabling sending the information on crashes of the application.
configuration.autoCrashTracking = NO;
// Set the configuration in AppMetricaCrashes.
[[AMAAppMetricaCrashes crashes] setConfiguration:configuration];
Determining the location
AppMetrica can determine the location of a device. Location accuracy depends on the configuration that the library uses for initialization:
-
With the
locationTracking
option enabled. For iOS, the option is enabled by default.The location is determined with accuracy to the city. You can retrieve this information in reports and via the Logs API.
The app requests GPS access. Battery consumption may increase.
-
With the
locationTracking
option disabled.The location is determined by the IP address with accuracy to the country. You can retrieve this information in reports and via the Logs API.
The app requests GPS access. Battery consumption does not increase.
Note
If you have enabled IP address masking, AppMetrica determines location with the accuracy to the country by the unmasked part of the IP address.
By default, the AppMetrica SDK is initialized with locationTracking
enabled, but it doesn't request permission to get location data. You should implement this using methods of the CLLocationManager class.
To initialize a library with locationTracking
disabled, set the locationTracking
property of the AppMetricaConfiguration
configuration to false
.
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Disabling sending information about the location of the device.
configuration.locationTracking = false
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
To disable locationTracking
after initializing the library, use the isLocationTrackingEnabled
property of the AppMetrica
class:
AppMetrica.isLocationTrackingEnabled = false
To initialize a library with locationTracking
disabled, set the locationTracking
property of the AMAAppMetricaConfiguration
configuration to NO
.
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Disabling sending information about the device location.
configuration.locationTracking = NO;
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
To disable locationTracking
after initializing the library, use the +setLocationTrackingEnabled:
method of the AMAAppMetrica
class:
AMAAppMetrica.locationTrackingEnabled = NO;
Setting device location manually
Before sending custom information about the device location, make sure that reporting is enabled.
By default, the device location is detected by the library.
To send custom device location, pass the CLLocation instance to the customLocation
property of the AppMetrica
class.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
AppMetrica.customLocation = locations.last
}
To send custom device location using the startup configuration, pass the CLLocation instance to the customLocation
property of the AppMetricaConfiguration
configuration.
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Set a custom location.
configuration.customLocation = CLLocation(latitude: 0, longitude: 0)
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
To send custom device location, pass the CLLocation instance to the setCustomLocation
method of the AMAAppMetrica
class.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
AMAAppMetrica.customLocation = newLocation;
}
To send custom device location using the startup configuration, pass the CLLocation instance to the customLocation
property of the AMAAppMetricaConfiguration
configuration.
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Set a custom location.
configuration.customLocation = [[CLLocation alloc] initWithLatitude:0 longitude:0];
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
Sending a custom event
To send a custom event without nested parameters, pass the following parameters to the reportEvent(name:onFailure:)
method of the AppMetrica
class:
name
: Short name or description of the event.onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
var message = "Updates installed"
AppMetrica.reportEvent(name: message, onFailure: { (error) in
print("DID FAIL TO REPORT EVENT: %@", message)
print("REPORT ERROR: %@", error.localizedDescription)
})
To send a custom event without nested parameters, pass the following parameters to the +reportEvent:onFailure:
method of the AMAAppMetrica
class:
message
: Short name or description of the event.onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
NSString *message = @"Updates installed";
[AMAAppMetrica reportEvent:message onFailure:^(NSError *error) {
NSLog(@"DID FAIL REPORT EVENT: %@", message);
NSLog(@"REPORT ERROR: %@", [error localizedDescription]);
}];
Sending a custom event with nested parameters
To send a custom event with nested parameters, pass the following parameters to the reportEvent(name:parameters:onFailure:)
method of the AppMetrica
class:
-
name
: Short name or description of the event. -
parameters
: Nested parameters as key-value pairs.The AppMetrica web interface displays up to five nesting levels for events. So if an event has six or more levels, only the top five are shown in the report. You can use the Reporting API to export up to ten levels.
-
onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
var message = "Updates installed"
let params = ["key1": "value1", "key2": "value2"]
AppMetrica.reportEvent(name: message, parameters: params, onFailure: { (error) in
print("DID FAIL REPORT EVENT: %@", message)
print("REPORT ERROR: %@", error.localizedDescription)
})
To send a custom event with nested parameters, pass the following parameters to the +reportEvent:parameters:onFailure:
method of the AMAAppMetrica
class:
-
message
: Short name or description of the event. -
parameters
: Nested parameters as key-value pairs.The AppMetrica web interface displays up to five nesting levels for events. So if an event has six or more levels, only the top five are shown in the report. You can use the Reporting API to export up to ten levels.
-
onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
NSString *message = @"Updates installed";
NSDictionary *params = @{@"key1": @"value1", @"key2": @"value2"};
[AMAAppMetrica reportEvent:message parameters:params onFailure:^(NSError *error) {
NSLog(@"DID FAIL REPORT EVENT: %@", message);
NSLog(@"REPORT ERROR: %@", [error localizedDescription]);
}];
For more information about events, see Events.
Sending an event from the WebView's JavaScript code
The AppMetrica SDK lets you send client events from JavaScript code. To do this, you need to connect the AppMetricaWebKit
module via the dependency management system that you're using.
Add the import:
import AppMetricaWebKit
Initialize the sending by calling the setupWebViewReporting(with:onFailure:)
method:
let userController = WKUserContentController()
AppMetrica.setupWebViewReporting(with: JSController(userContentController:userController), onFailure: nil)
userController.add(myHandler, name: myScriptName)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userController;
let webView = WKWebView(frame: .zero, configuration: configuration)
Add the import:
#import <AppMetricaWebKit/AppMetricaWebKit.h>
Initialize the sending by calling the +setupWebViewReporting:onFailure:
method:
WKUserContentController *userController = [[WKUserContentController alloc] init];
[AMAAppMetrica setupWebViewReporting:[[AMAJSController alloc] initWithUserContentController:userController] onFailure:nil];
[userController addScriptMessageHandler:myHandler name:myScriptName];
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = userController;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
Call this method before loading any content. We recommend calling this method before creating a webview and before adding your scripts to WKUserContentController.
To send an event from JavaScript code, use the reportEvent(name, value)
method in the AppMetrica interface:
function buttonClicked() {
AppMetrica.reportEvent('Button clicked!', '{}');
}
Arguments of the reportEvent
method:
name
: A string. Can't benull
or empty.value
: A JSON string. Can benull
.
Sending an error message
To send an error message, you need to connect the AppMetricaCrashes
module via the dependency management system that you're using.
To send a custom error message, add the import:
import AppMetricaCrashes
Then use the methods of the AppMetricaCrashes
class and the AppMetricaCrashReporting
protocol:
report(error:onFailure:)
report(error:options:onFailure:)
report(nserror:onFailure:)
report(nserror:options:onFailure:)
To send error messages, you can use the standard NSError class, the simplified AppMetricaError
class, or the ErrorRepresentable
protocol.
To send a custom error message, add the import:
#import <AppMetricaCrashes/AppMetricaCrashes.h>
Then use the methods of the AMAAppMetricaCrashes
class and the AMAAppMetricaCrashReporting
protocol:
-reportError:onFailure:
-reportError:options:onFailure:
-reportNSError:onFailure:
-reportNSError:options:onFailure:
To send error messages, you can use the standard NSError class, the simplified AMAError
class, or the AMAErrorRepresentable
protocol.
Example with NSError
If errors are sent using the NSError class, they're grouped by the domain domain and the code error code.
let firstError = NSError(domain: "io.appmetrica.error-a", code: 12, userInfo: [
BacktraceErrorKey: Thread.callStackReturnAddresses,
NSLocalizedDescriptionKey: "Error A"
])
AppMetricaCrashes.crashes().report(nserror: firstError)
NSError *firstError = [NSError errorWithDomain:@"io.appmetrica.error-a"
code:12
userInfo:@{
AMABacktraceErrorKey: NSThread.callStackReturnAddresses,
NSLocalizedDescriptionKey: @"Error A"
}];
[[AMAAppMetricaCrashes crashes] reportNSError:firstError onFailure:nil];
Example with AppMetricaError
If errors are sent using the AppMetricaError
class or the ErrorRepresentable
protocol, they're grouped by the identifier
.
let underlyingError = AppMetricaError(identifier: "Underlying AMAError")
let error = AppMetricaError(
identifier: "AMAError identifier",
message: "Another custom message",
parameters: [
"foo": "bar"
],
backtrace: Thread.callStackReturnAddresses,
underlyingError: underlyingError
)
AppMetricaCrashes.crashes().report(error: error)
If errors are sent using the AMAError
class or the AMAErrorRepresentable
protocol, they're grouped by the identifier
.
AMAError *underlyingError = [AMAError errorWithIdentifier:@"Underlying AMAError"];
AMAError *error = [AMAError errorWithIdentifier:@"AMAError identifier"
message:@"Another custom message"
parameters:@{ @"foo": @"bar" }
backtrace:NSThread.callStackReturnAddresses
underlyingError:underlyingError];
[[AMAAppMetricaCrashes crashes] reportError:error onFailure:nil];
Don't use variable values as grouping IDs. Otherwise, the number of groups increases and it becomes difficult to analyze them.
Sending ProfileId
If you don't configure ProfileId
sending in the SDK, the web interface displays the appmetrica_device_id
value.
To send the ProfileId
, use the userProfileID
property of the AppMetrica
class.
AppMetrica.userProfileID = "id"
To send the ProfileId
, use the +setUserProfileID:
method of the AMAAppMetrica
class.
AMAAppMetrica.userProfileID = @"id";
Sending profile attributes
To send profile attributes, pass the following parameters to the reportUserProfile(_:onFailure:)
method of the AppMetrica
class:
userProfile
: TheUserProfile
instance that contains an array of attribute updates. Profile attributes are created by methods of theProfileAttribute
class.onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
let profile = MutableUserProfile()
// Updating a single user profile attribute.
let timeLeftAttribute = ProfileAttribute.customCounter("time_left")
profile.apply(timeLeftAttribute.withDelta(-4.42))
// Updating multiple attributes.
profile.apply(from: [
// Updating predefined attributes.
ProfileAttribute.name().withValue("John"),
ProfileAttribute.gender().withValue(GenderType.male),
ProfileAttribute.birthDate().withAge(24),
ProfileAttribute.notificationsEnabled().withValue(false),
// Updating custom attributes.
ProfileAttribute.customString("born_in").withValueIfUndefined("Moscow"),
ProfileAttribute.customString("address").withValueReset(),
ProfileAttribute.customNumber("age").withValue(24),
ProfileAttribute.customCounter("logins_count").withDelta(1),
ProfileAttribute.customBool("has_premium").withValue(true)
])
// ProfieID is set using the method of the AppMetrica class.
AppMetrica.userProfileID = "id"
// Sending profile attributes.
AppMetrica.reportUserProfile(profile, onFailure: { (error) in
print("REPORT ERROR: %@", error.localizedDescription)
})
To send profile attributes, pass the following parameters to the +reportUserProfile:onFailure:
method of the AMAAppMetrica
class:
userProfile
: TheAMAUserProfile
instance that contains an array of attribute updates. To create profile attributes, use methods of theAMAProfileAttribute
class.onFailure
: The block the error is passed to. If you do not want to track the error, passnil
for this block.
AMAMutableUserProfile *profile = [[AMAMutableUserProfile alloc] init];
// Updating a single user profile attribute.
id<AMACustomCounterAttribute> timeLeftAttribute = [AMAProfileAttribute customCounter:@"time_left"];
[profile apply:[timeLeftAttribute withDelta:-4.42]];
// Updating multiple attributes.
[profile applyFromArray:@[
// Updating predefined attributes.
[[AMAProfileAttribute name] withValue:@"John"],
[[AMAProfileAttribute gender] withValue:AMAGenderTypeMale],
[[AMAProfileAttribute birthDate] withAge:24],
[[AMAProfileAttribute notificationsEnabled] withValue:NO],
// Updating custom attributes.
[[AMAProfileAttribute customString:@"born_in"] withValueIfUndefined:@"Moscow"],
[[AMAProfileAttribute customString:@"address"] withValueReset],
[[AMAProfileAttribute customNumber:@"age"] withValue:24],
[[AMAProfileAttribute customCounter:@"logins_count"] withDelta:1],
[[AMAProfileAttribute customBool:@"has_premium"] withValue:YES]
]];
// ProfieID is set using the method of the AMAAppMetrica class.
[AMAAppMetrica setUserProfileID:@"id"];
// Sending profile attributes.
[AMAAppMetrica reportUserProfile:[profile copy] onFailure:^(NSError *error) {
NSLog(@"Error: %@", error);
}];
Sending E-commerce events
AppMetrica doesn't let you segment E-commerce events into test and non-test events. If you use the main API key for debugging purchases, the test events are included in general statistics. Therefore, to debug E-commerce event sending, use a reporter to send statistics to the additional API key.
Step 1. Configure sending E-commerce events to the test API key
For different user actions, there are appropriate types of E-commerce events. To create a specific event type, use the appropriate ECommerce
class method.
The examples below show how to send specific types of events:
Opening a page
// Creating a screen object.
let screen = ECommerceScreen(
name: "ProductCardScreen",
categoryComponents: ["Promos", "Hot deal"],
searchQuery: "danissimo maple syrup",
payload: ["full_screen": "true"]
)
// Sending an e-commerce event.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportECommerce(.showScreenEvent(screen: screen))
}
// Creating a screen object.
AMAECommerceScreen *screen = [[AMAECommerceScreen alloc] initWithName:@"ProductCardScreen"
categoryComponents:@[ @"Promos", @"Hot deal" ]
searchQuery:@"danissimo maple syrup"
payload:@{ @"full_screen": @"true" }];
// Sending an e-commerce event.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportECommerce:[AMAECommerce showScreenEventWithScreen:screen] onFailure:nil];
Viewing a product card
// Creating a screen object.
let screen = ECommerceScreen(
name: "ProductCardScreen",
categoryComponents: ["Promos", "Hot deal"],
searchQuery: "danissimo maple syrup",
payload: ["full_screen": "true"]
)
// Creating an actualPrice object.
let actualPrice = ECommercePrice(
fiat: .init(unit: "USD", value: .init(string: "4.53")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30570000")),
.init(unit: "iron", value: .init(string: "26.89")),
.init(unit: "gold", value: .init(string: "5.1")),
]
)
// Creating a product object.
let product = ECommerceProduct(
sku: "779213",
name: "Danissimo curd product 5.9%, 130 g",
categoryComponents: ["Groceries", "Dairy products", "Yogurts"],
payload: ["full_screen": "true"],
actualPrice: actualPrice,
originalPrice: .init(
fiat: .init(unit: "USD", value: .init(string: "5.78")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30590000")),
.init(unit: "iron", value: .init(string: "26.92")),
.init(unit: "gold", value: .init(string: "5.5")),
]
),
promoCodes: ["BT79IYX", "UT5412EP"]
)
// Sending an e-commerce event.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportECommerce(.showProductCardEvent(product: product, screen: screen))
}
// Creating a screen object.
AMAECommerceScreen *screen = [[AMAECommerceScreen alloc] initWithName:@"ProductCardScreen"
categoryComponents:@[ @"Promos", @"Hot deal" ]
searchQuery:@"danissimo maple syrup"
payload:@{ @"full_screen": @"true" }];
// Creating an actualPrice object.
AMAECommerceAmount *actualFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"4.53"]];
AMAECommerceAmount *woodActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30570000"]];
AMAECommerceAmount *ironActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.89"]];
AMAECommerceAmount *goldActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.1"]];
AMAECommercePrice *actualPrice = [[AMAECommercePrice alloc] initWithFiat:actualFiat
internalComponents:@[ woodActualPrice, ironActualPrice, goldActualPrice ]];
// Creating an originalPrice object.
AMAECommerceAmount *originalFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"5.78"]];
AMAECommerceAmount *woodOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30590000"]];
AMAECommerceAmount *ironOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.92"]];
AMAECommerceAmount *goldOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.5"]];
AMAECommercePrice *originalPrice = [[AMAECommercePrice alloc] initWithFiat:originalFiat
internalComponents:@[ woodOriginalPrice, ironOriginalPrice, goldOriginalPrice ]];
// Creating a product object.
AMAECommerceProduct *product = [[AMAECommerceProduct alloc] initWithSKU:@"779213"
name:@"Danissimo curd product 5.9%, 130 g"
categoryComponents:@[ @"Groceries", @"Dairy products", @"Yogurts" ]
payload:@{ @"full_screen" : @"true" }
actualPrice:actualPrice
originalPrice:originalPrice
promoCodes:@[ @"BT79IYX", @"UT5412EP" ]];
// Sending an e-commerce event.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportECommerce:[AMAECommerce showProductCardEventWithProduct:product screen:screen] onFailure:nil];
Viewing a product page
// Creating a screen object.
let screen = ECommerceScreen(
name: "ProductCardScreen",
categoryComponents: ["Promos", "Hot deal"],
searchQuery: "danissimo maple syrup",
payload: ["full_screen": "true"]
)
// Creating an actualPrice object.
let actualPrice = ECommercePrice(
fiat: .init(unit: "USD", value: .init(string: "4.53")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30570000")),
.init(unit: "iron", value: .init(string: "26.89")),
.init(unit: "gold", value: .init(string: "5.1")),
]
)
// Creating a product object.
let product = ECommerceProduct(
sku: "779213",
name: "Danissimo curd product 5.9%, 130 g",
categoryComponents: ["Groceries", "Dairy products", "Yogurts"],
payload: ["full_screen": "true"],
actualPrice: actualPrice,
originalPrice: .init(
fiat: .init(unit: "USD", value: .init(string: "5.78")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30590000")),
.init(unit: "iron", value: .init(string: "26.92")),
.init(unit: "gold", value: .init(string: "5.5")),
]
),
promoCodes: ["BT79IYX", "UT5412EP"]
)
// Creating a referrer object.
let referrer = ECommerceReferrer(type: "button", identifier: "76890", screen: screen)
// Sending an e-commerce event.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportECommerce(.showProductDetailsEvent(product: product, referrer: referrer))
}
// Creating a screen object.
AMAECommerceScreen *screen = [[AMAECommerceScreen alloc] initWithName:@"ProductCardScreen"
categoryComponents:@[ @"Promos", @"Hot deal" ]
searchQuery:@"danissimo maple syrup"
payload:@{ @"full_screen": @"true" }];
// Creating an actualPrice object.
AMAECommerceAmount *actualFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"4.53"]];
AMAECommerceAmount *woodActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30570000"]];
AMAECommerceAmount *ironActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.89"]];
AMAECommerceAmount *goldActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.1"]];
AMAECommercePrice *actualPrice = [[AMAECommercePrice alloc] initWithFiat:actualFiat
internalComponents:@[ woodActualPrice, ironActualPrice, goldActualPrice ]];
// Creating an originalPrice object.
AMAECommerceAmount *originalFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"5.78"]];
AMAECommerceAmount *woodOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30590000"]];
AMAECommerceAmount *ironOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.92"]];
AMAECommerceAmount *goldOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.5"]];
AMAECommercePrice *originalPrice = [[AMAECommercePrice alloc] initWithFiat:originalFiat
internalComponents:@[ woodOriginalPrice, ironOriginalPrice, goldOriginalPrice ]];
// Creating a product object.
AMAECommerceProduct *product = [[AMAECommerceProduct alloc] initWithSKU:@"779213"
name:@"Danissimo curd product 5.9%, 130 g"
categoryComponents:@[ @"Groceries", @"Dairy products", @"Yogurts" ]
payload:@{ @"full_screen" : @"true" }
actualPrice:actualPrice
originalPrice:originalPrice
promoCodes:@[ @"BT79IYX", @"UT5412EP" ]];
// Creating a referrer object.
AMAECommerceReferrer *referrer = [[AMAECommerceReferrer alloc] initWithType:@"button"
identifier:@"76890"
screen:screen];
// Sending an e-commerce event.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportECommerce:[AMAECommerce showProductDetailsEventWithProduct:product referrer:referrer] onFailure:nil];
Adding or removing an item to/from the cart
// Creating a screen object.
let screen = ECommerceScreen(
name: "ProductCardScreen",
categoryComponents: ["Promos", "Hot deal"],
searchQuery: "danissimo maple syrup",
payload: ["full_screen": "true"]
)
// Creating an actualPrice object.
let actualPrice = ECommercePrice(
fiat: .init(unit: "USD", value: .init(string: "4.53")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30570000")),
.init(unit: "iron", value: .init(string: "26.89")),
.init(unit: "gold", value: .init(string: "5.1")),
]
)
// Creating a product object.
let product = ECommerceProduct(
sku: "779213",
name: "Danissimo curd product 5.9%, 130 g",
categoryComponents: ["Groceries", "Dairy products", "Yogurts"],
payload: ["full_screen": "true"],
actualPrice: actualPrice,
originalPrice: .init(
fiat: .init(unit: "USD", value: .init(string: "5.78")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30590000")),
.init(unit: "iron", value: .init(string: "26.92")),
.init(unit: "gold", value: .init(string: "5.5")),
]
),
promoCodes: ["BT79IYX", "UT5412EP"]
)
// Creating a referrer object.
let referrer = ECommerceReferrer(type: "button", identifier: "76890", screen: screen)
// Creating a cartItem object.
let addedItems = ECommerceCartItem(
product: product,
quantity: .init(string: "1"),
revenue: actualPrice,
referrer: referrer
)
// Sending an e-commerce event.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportECommerce(.addCartItemEvent(cartItem: addedItems))
// Or:
reporter.reportECommerce(.removeCartItemEvent(cartItem: addedItems))
}
// Creating a screen object.
AMAECommerceScreen *screen = [[AMAECommerceScreen alloc] initWithName:@"ProductCardScreen"
categoryComponents:@[ @"Promos", @"Hot deal" ]
searchQuery:@"danissimo maple syrup"
payload:@{ @"full_screen": @"true" }];
// Creating an actualPrice object.
AMAECommerceAmount *actualFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"4.53"]];
AMAECommerceAmount *woodActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30570000"]];
AMAECommerceAmount *ironActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.89"]];
AMAECommerceAmount *goldActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.1"]];
AMAECommercePrice *actualPrice = [[AMAECommercePrice alloc] initWithFiat:actualFiat
internalComponents:@[ woodActualPrice, ironActualPrice, goldActualPrice ]];
// Creating an originalPrice object.
AMAECommerceAmount *originalFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"5.78"]];
AMAECommerceAmount *woodOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30590000"]];
AMAECommerceAmount *ironOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.92"]];
AMAECommerceAmount *goldOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.5"]];
AMAECommercePrice *originalPrice = [[AMAECommercePrice alloc] initWithFiat:originalFiat
internalComponents:@[ woodOriginalPrice, ironOriginalPrice, goldOriginalPrice ]];
// Creating a product object.
AMAECommerceProduct *product = [[AMAECommerceProduct alloc] initWithSKU:@"779213"
name:@"Danissimo curd product 5.9%, 130 g"
categoryComponents:@[ @"Groceries", @"Dairy products", @"Yogurts" ]
payload:@{ @"full_screen" : @"true" }
actualPrice:actualPrice
originalPrice:originalPrice
promoCodes:@[ @"BT79IYX", @"UT5412EP" ]];
// Creating a referrer object.
AMAECommerceReferrer *referrer = [[AMAECommerceReferrer alloc] initWithType:@"button"
identifier:@"76890"
screen:screen];
// Creating a cartItem object.
NSDecimalNumber *quantity = [NSDecimalNumber decimalNumberWithString:@"1"];
AMAECommerceCartItem *addedItems = [[AMAECommerceCartItem alloc] initWithProduct:product
quantity:quantity
revenue:actualPrice
referrer:referrer];
// Sending an e-commerce event.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportECommerce:[AMAECommerce addCartItemEventWithItem:addedItems] onFailure:nil];
// Or:
[reporter reportECommerce:[AMAECommerce removeCartItemEventWithItem:addedItems] onFailure:nil];
Starting and completing a purchase
// Creating a screen object.
let screen = ECommerceScreen(
name: "ProductCardScreen",
categoryComponents: ["Promos", "Hot deal"],
searchQuery: "danissimo maple syrup",
payload: ["full_screen": "true"]
)
// Creating an actualPrice object.
let actualPrice = ECommercePrice(
fiat: .init(unit: "USD", value: .init(string: "4.53")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30570000")),
.init(unit: "iron", value: .init(string: "26.89")),
.init(unit: "gold", value: .init(string: "5.1")),
]
)
// Creating a product object.
let product = ECommerceProduct(
sku: "779213",
name: "Danissimo curd product 5.9%, 130 g",
categoryComponents: ["Groceries", "Dairy products", "Yogurts"],
payload: ["full_screen": "true"],
actualPrice: actualPrice,
originalPrice: .init(
fiat: .init(unit: "USD", value: .init(string: "5.78")),
internalComponents: [
.init(unit: "wood", value: .init(string: "30590000")),
.init(unit: "iron", value: .init(string: "26.92")),
.init(unit: "gold", value: .init(string: "5.5")),
]
),
promoCodes: ["BT79IYX", "UT5412EP"]
)
// Creating a referrer object.
let referrer = ECommerceReferrer(type: "button", identifier: "76890", screen: screen)
// Creating a cartItem object.
let addedItems = ECommerceCartItem(
product: product,
quantity: .init(string: "1"),
revenue: actualPrice,
referrer: referrer
)
// Creating an order object.
let order = ECommerceOrder(
identifier: "88528768",
cartItems: [addedItems],
payload: ["black_friday": "true"]
)
// Sending an e-commerce event.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportECommerce(.beginCheckoutEvent(order:order))
reporter.reportECommerce(.purchaseEvent(order: order))
}
// Creating a screen object.
AMAECommerceScreen *screen = [[AMAECommerceScreen alloc] initWithName:@"ProductCardScreen"
categoryComponents:@[ @"Promos", @"Hot deal" ]
searchQuery:@"danissimo maple syrup"
payload:@{ @"full_screen": @"true" }];
// Creating an actualPrice object.
AMAECommerceAmount *actualFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"4.53"]];
AMAECommerceAmount *woodActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30570000"]];
AMAECommerceAmount *ironActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.89"]];
AMAECommerceAmount *goldActualPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.1"]];
AMAECommercePrice *actualPrice = [[AMAECommercePrice alloc] initWithFiat:actualFiat
internalComponents:@[ woodActualPrice, ironActualPrice, goldActualPrice ]];
// Creating an originalPrice object.
AMAECommerceAmount *originalFiat =
[[AMAECommerceAmount alloc] initWithUnit:@"USD" value:[NSDecimalNumber decimalNumberWithString:@"5.78"]];
AMAECommerceAmount *woodOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"wood" value:[NSDecimalNumber decimalNumberWithString:@"30590000"]];
AMAECommerceAmount *ironOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"iron" value:[NSDecimalNumber decimalNumberWithString:@"26.92"]];
AMAECommerceAmount *goldOriginalPrice =
[[AMAECommerceAmount alloc] initWithUnit:@"gold" value:[NSDecimalNumber decimalNumberWithString:@"5.5"]];
AMAECommercePrice *originalPrice = [[AMAECommercePrice alloc] initWithFiat:originalFiat
internalComponents:@[ woodOriginalPrice, ironOriginalPrice, goldOriginalPrice ]];
// Creating a product object.
AMAECommerceProduct *product = [[AMAECommerceProduct alloc] initWithSKU:@"779213"
name:@"Danissimo curd product 5.9%, 130 g"
categoryComponents:@[ @"Groceries", @"Dairy products", @"Yogurts" ]
payload:@{ @"full_screen" : @"true" }
actualPrice:actualPrice
originalPrice:originalPrice
promoCodes:@[ @"BT79IYX", @"UT5412EP" ]];
// Creating a referrer object.
AMAECommerceReferrer *referrer = [[AMAECommerceReferrer alloc] initWithType:@"button"
identifier:@"76890"
screen:screen];
// Creating a cartItem object.
NSDecimalNumber *quantity = [NSDecimalNumber decimalNumberWithString:@"1"];
AMAECommerceCartItem *addedItems = [[AMAECommerceCartItem alloc] initWithProduct:product
quantity:quantity
revenue:actualPrice
referrer:referrer];
// Creating an order object.
AMAECommerceOrder *order = [[AMAECommerceOrder alloc] initWithIdentifier:@"88528768"
cartItems:@[ addedItems ]
payload:@{ @"black_friday" : @"true"}];
// Sending an e-commerce event.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportECommerce:[AMAECommerce beginCheckoutEventWithOrder:order] onFailure:nil];
[reporter reportECommerce:[AMAECommerce purchaseEventWithOrder:order] onFailure:nil];
Step 2. Check the test app report
Make in-app test purchases. After a while, check the Purchase analysis report in the AppMetrica interface. Make sure that the report shows E-commerce events.
For more information about the report, see Purchase analysis.
Step 3. Configure sending events to the main API key
After successful testing, configure sending E-commerce events to the main API key.
To send the ECommerce
object to the main API key, use the reportECommerce(_:onFailure:)
method of the AppMetrica
class.
// ...
// Sending an e-commerce event.
AppMetrica.reportECommerce(.showScreenEvent(screen: screen))
To send the AMAECommerce
instance to the main API key, use the +reportECommerce:onFailure:
method of the AMAAppMetrica
class.
// ...
// Sending an e-commerce event.
[AMAAppMetrica reportECommerce:[AMAECommerce showScreenEventWithScreen:screen] onFailure:nil];
Sending Revenue
AppMetrica supports validation of purchases implemented using the StoreKit library. Validation lets you filter purchases made from hacked apps. If validation is enabled and a purchase fails it, this purchase isn't shown in reports.
Note
To validate purchases, enable the validation in the settings.
Step 1. Test sending Revenue
AppMetrica doesn't let you segment between test and non-test revenue. If you use the main API key for debugging purchases, the test purchases are included in general statistics. Therefore, to debug Revenue sending, use a reporter to send statistics to the additional API key.
This section outlines the steps for sending Revenue to the additional API key:
With validation
To validate purchases on iOS, configure sending the transactionID
field and receiptData
where you implement the transaction completion:
- Initialize the
MutableRevenueInfo
instance. - To validate a purchase, specify
transactionID
andreceiptData
. You should receive them before invokingSKPaymentQueue.default ().finishTransaction(transaction)
. - Send the
MutableRevenueInfo
instance to the test API key using theAppMetricaReporting
reporter. For more information about reporters, see Sending statistics to an additional API key.
func completeTransaction(_ transaction: SKPaymentTransaction) {
// ...
let price = NSDecimalNumber(string: "2100.5")
// Initializing the Revenue instance.
let revenueInfo = MutableRevenueInfo(priceDecimal: price, currency: "BYN")
revenueInfo.productID = "TV soundbar"
revenueInfo.quantity = 2
revenueInfo.payload = ["source": "AppStore"]
// Set purchase information for validation.
if let url = Bundle.main.appStoreReceiptURL, let data = try? Data(contentsOf: url), let transactionID = transaction.transactionIdentifier {
revenueInfo.transactionID = transactionID
revenueInfo.receiptData = data
}
// Sending the Revenue instance using reporter.
guard let reporter = AppMetrica.reporter(for: "Testing API key") else {
print("Failed to create AppMetrica reporter")
return
}
reporter.reportRevenue(revenueInfo, onFailure: { (error) in
print("Revenue error: \(error.localizedDescription)")
})
// Remove the transaction from the payment queue.
SKPaymentQueue.default().finishTransaction(transaction)
}
- Initialize the
AMAMutableRevenueInfo
instance. - To validate a purchase, specify
transactionID
andreceiptData
. The must be received before[[SKPaymentQueue defaultQueue] finishTransaction:transaction]
is invoked. - Send the
AMAMutableRevenueInfo
instance to the test API key using theAMAAppMetricaReporting
reporter. For more information about reporters, see Sending statistics to an additional API key.
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
// ...
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:@"2100.5"];
// Initializing the Revenue instance.
AMAMutableRevenueInfo *revenueInfo = [[AMAMutableRevenueInfo alloc] initWithPriceDecimal:price currency:@"BYN"];
revenueInfo.productID = @"TV soundbar";
revenueInfo.quantity = 2;
revenueInfo.payload = @{ @"source": @"AppStore" };
// Set purchase information for validation.
revenueInfo.transactionID = transaction.transactionIdentifier;
revenueInfo.receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
// Sending the Revenue instance using reporter.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportRevenue:[revenueInfo copy] onFailure:^(NSError *error) {
NSLog(@"Revenue error: %@", error);
}];
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
Without validation
To send information about a purchase without validation:
-
Initialize the
MutableRevenueInfo
instance. -
(Optional) To group purchases by
OrderID
, specify it in thepayload
property.Note
If the
OrderID
is not specified, AppMetrica generates the ID automatically. -
Send the
MutableRevenueInfo
instance to the test API key using theAppMetricaReporting
reporter. For more information about reporters, see Sending statistics to an additional API key.
let price = NSDecimalNumber(string: "2100.5")
// Initializing the Revenue instance.
let revenueInfo = MutableRevenueInfo(priceDecimal: price, currency: "BYN")
revenueInfo.productID = "TV soundbar"
revenueInfo.quantity = 2
// To group purchases, set the OrderID parameter in the payload property.
revenueInfo.payload = ["OrderID": "Identifier", "source": "AppStore"]
// Sending the Revenue instance using reporter.
if let reporter = AppMetrica.reporter(for: "Testing API key") {
reporter.reportRevenue(revenueInfo, onFailure: { (error) in
print("Revenue error: \(error.localizedDescription)")
})
}
-
Initialize the
AMAMutableRevenueInfo
instance. -
(Optional) To group purchases by
OrderID
, specify it in thepayload
property.Note
If the
OrderID
is not specified, AppMetrica generates the ID automatically. -
Send the
AMAMutableRevenueInfo
instance to the test API key using theAMAAppMetricaReporting
reporter. For more information about reporters, see Sending statistics to an additional API key.
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:@"2100.5"];
// Initializing the Revenue instance.
AMAMutableRevenueInfo *revenueInfo = [[AMAMutableRevenueInfo alloc] initWithPriceDecimal:price currency:@"BYN"];
revenueInfo.productID = @"TV soundbar";
revenueInfo.quantity = 2;
// Setting the OrderID parameter in the payload property to group purchases
revenueInfo.payload = @{ @"OrderID": @"Identifier", @"source": @"AppStore" };
// Sending the Revenue instance using reporter.
id<AMAAppMetricaReporting> reporter = [AMAAppMetrica reporterForAPIKey:@"Testing API key"];
[reporter reportRevenue:[revenueInfo copy] onFailure:^(NSError *error) {
NSLog(@"Revenue error: %@", error);
}];
Step 2. Configure sending Revenue to the main API key
After successful testing, configure sending Revenue to the main API key.
To send the MutableRevenueInfo
instance to the main API key, use the reportRevenue(_:onFailure:)
method of the AppMetrica
class.
// ...
// Sending the Revenue instance.
AppMetrica.reportRevenue(revenueInfo, onFailure: { (error) in
print("Revenue error: \(error)")
})
To send the AMAMutableRevenueInfo
instance to the main API key, use the +reportRevenue:onFailure:
method of the AMAAppMetrica
class.
// ...
// Sending the Revenue instance.
[AMAAppMetrica reportRevenue:[revenueInfo copy] onFailure:^(NSError *error) {
NSLog(@"Revenue error: %@", error);
}];
Sending Ad Revenue data
Step 1. Make sure that the SDK is activated
Activation example:
let configuration = AppMetricaConfiguration.init(apiKey: "API key")
AppMetrica.activate(with: configuration!)
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithApiKey:@"API_key"];
[AMAAppMetrica activateWithConfiguration:configuration];
Step 2. Set up sending Ad Revenue data
-
Import the required modules:
SwiftObjective-Cimport AppMetricaCore import AppLovinSDK
#import <AppMetricaCore/AppMetricaCore.h> #import <AppLovinSDK/AppLovinSDK.h>
-
Add a helper extension for
MAAdFormat
:SwiftObjective-Cextension MAAdFormat { var appMetricaAdType: AdType { switch self { case .banner: return .banner case .interstitial: return .interstitial case .rewarded: return .rewarded case .native: return .native case .mrec: return .mrec default: return .other } } }
@implementation MAAdFormat (AppMetricaAdType) - (AdType)appMetricaAdType { switch (self) { case MAAdFormat.banner: return AdTypeBanner; case MAAdFormat.interstitial: return AdTypeInterstitial; case MAAdFormat.rewarded: return AdTypeRewarded; case MAAdFormat.native: return AdTypeNative; case MAAdFormat.mrec: return AdTypeMrec; default: return AdTypeOther; } } @end
-
Implement
MAAdRevenueDelegate
:SwiftObjective-Cclass AdRevenueReporter: NSObject, MAAdRevenueDelegate { func didPayRevenue(for ad: MAAd) { // Create a MutableAdRevenueInfo object let adRevenueInfo = MutableAdRevenueInfo(adRevenue: NSDecimalNumber(value: ad.revenue), currency: "USD") // Set additional properties adRevenueInfo.adType = ad.format.appMetricaAdType adRevenueInfo.adNetwork = ad.networkName adRevenueInfo.adUnitID = ad.adUnitIdentifier adRevenueInfo.adPlacementName = ad.placement adRevenueInfo.precision = ad.revenuePrecision // Additional information can be added to payload if needed adRevenueInfo.payload = [ "adType": ad.format.label, "countryCode": ALSdk.shared().configuration.countryCode, "networkPlacement": ad.networkPlacement ] // Report the ad revenue to AppMetrica AppMetrica.reportAdRevenue(adRevenueInfo) } }
#import <AppMetricaCore/AppMetricaCore.h> #import <AppLovinSDK/AppLovinSDK.h>
-
Import the required modules:
SwiftObjective-Cimport AppMetricaCore import FairBidSDK
#import <AppMetricaCore/AppMetricaCore.h> #import <FairBidSDK/FairBidSDK.h>
-
Create a function for passing ad revenue data to AppMetrica:
SwiftObjective-Cfunc reportToAppMetrica(_ impressionData: FYBImpressionData, placementId: String, adType: AdType) { let revenue = impressionData.netPayout.map { NSDecimalNumber(decimal: $0.decimalValue) } ?? .zero let currency = impressionData.currency ?? "USD" let adRevenueInfo = MutableAdRevenueInfo(adRevenue: revenue, currency: currency) adRevenueInfo.adType = adType adRevenueInfo.adNetwork = impressionData.demandSource adRevenueInfo.adUnitID = impressionData.creativeId adRevenueInfo.precision = impressionData.priceAccuracy.appMetricaPrecision AppMetrica.reportAdRevenue(adRevenueInfo) { error in print("Failed to report ad revenue to AppMetrica: \(error)") } }
void reportToAppMetrica(FYBImpressionData *impressionData, NSString *placementId, AdType adType) { NSDecimalNumber *revenue = impressionData.netPayout ? [[NSDecimalNumber alloc] initWithDecimal:impressionData.netPayout.decimalValue] : [NSDecimalNumber zero]; NSString *currency = impressionData.currency ? impressionData.currency : @"USD"; MutableAdRevenueInfo *adRevenueInfo = [[MutableAdRevenueInfo alloc] initWithAdRevenue:revenue currency:currency]; adRevenueInfo.adType = adType; adRevenueInfo.adNetwork = impressionData.demandSource; adRevenueInfo.adUnitID = impressionData.creativeId; adRevenueInfo.precision = [impressionData.priceAccuracy appMetricaPrecision]; [AppMetrica reportAdRevenue:adRevenueInfo completion:^(NSError *error) { if (error) { NSLog(@"Failed to report ad revenue to AppMetrica: %@", error); } }]; }
-
Add an extension for converting Fyber prices to the AppMetrica format:
SwiftObjective-Cextension FYBImpressionDataPriceAccuracy { var appMetricaPrecision: String { switch self { case .undisclosed: return "undisclosed" case .predicted: return "predicted" case .programmatic: return "programmatic" @unknown default: return "unknown" } } }
@implementation NSNumber (FYBImpressionDataPriceAccuracyAppMetricaPrecision) + (NSString *)appMetricaPrecisionForFYBImpressionDataPriceAccuracy:(FYBImpressionDataPriceAccuracy)accuracy { switch (accuracy) { case FYBImpressionDataPriceAccuracyUndisclosed: return @"undisclosed"; case FYBImpressionDataPriceAccuracyPredicted: return @"predicted"; case FYBImpressionDataPriceAccuracyProgrammatic: return @"programmatic"; default: return @"unknown"; } } @end
-
Create a function for sending Offerwall impression reports to AppMetrica:
SwiftObjective-Cfunc reportOfferWallShowToAppMetrica(placementId: String) { let adRevenueInfo = MutableAdRevenueInfo(adRevenue: NSDecimalNumber.zero, currency: "USD") adRevenueInfo.adType = .other adRevenueInfo.adUnitID = placementId AppMetrica.reportAdRevenue(adRevenueInfo) { error in print("Failed to report OfferWall show to AppMetrica: \(error)") } }
- (void)reportOfferWallShowToAppMetricaWithPlacementId:(NSString *)placementId { YMMMutableAdRevenueInfo *adRevenueInfo = [[YMMMutableAdRevenueInfo alloc] initWithAdRevenue:[NSDecimalNumber zero] currency:@"USD"]; adRevenueInfo.adType = YMMAdTypeOther; adRevenueInfo.adUnitID = placementId; [YMMYandexMetrica reportAdRevenueWithInfo:adRevenueInfo completionHandler:^(NSError * _Nullable error) { if (error) { NSLog(@"Failed to report OfferWall show to AppMetrica: %@", error); } }]; }
-
Create delegates and their corresponding methods for each ad format:
SwiftObjective-Cclass YourBannerDelegate: NSObject, FYBBannerDelegate { func bannerDidShow(_ banner: FYBBannerAdView, impressionData: FYBImpressionData) { reportToAppMetrica(impressionData, placementId: banner.options.placementId, adType: .banner) } // Implement other delegate methods as needed } class YourInterstitialDelegate: NSObject, FYBInterstitialDelegate { func interstitialDidShow(_ placementId: String, impressionData: FYBImpressionData) { reportToAppMetrica(impressionData, placementId: placementId, adType: .interstitial) } // Implement other delegate methods as needed } class YourRewardedDelegate: NSObject, FYBRewardedDelegate { func rewardedDidShow(_ placementId: String, impressionData: FYBImpressionData) { reportToAppMetrica(impressionData, placementId: placementId, adType: .rewarded) } // Implement other delegate methods as needed } class YourOfferWallDelegate: NSObject, OfferWallDelegate { func didShow(_ placementId: String?) { reportOfferWallShowToAppMetrica(placementId: placementId ?? "unknown") } // Implement other delegate methods as needed }
// YourBannerDelegate @interface YourBannerDelegate : NSObject <FYBBannerDelegate> @end @implementation YourBannerDelegate - (void)bannerDidShow:(FYBBannerAdView *)banner impressionData:(FYBImpressionData *)impressionData { [self reportToAppMetricaWithImpressionData:impressionData placementId:banner.options.placementId adType:AdTypeBanner]; } // Implement other delegate methods as needed @end // YourInterstitialDelegate @interface YourInterstitialDelegate : NSObject <FYBInterstitialDelegate> @end @implementation YourInterstitialDelegate - (void)interstitialDidShowWithPlacementId:(NSString *)placementId impressionData:(FYBImpressionData *)impressionData { [self reportToAppMetricaWithImpressionData:impressionData placementId:placementId adType:AdTypeInterstitial]; } // Implement other delegate methods as needed @end // YourRewardedDelegate @interface YourRewardedDelegate : NSObject <FYBRewardedDelegate> @end @implementation YourRewardedDelegate - (void)rewardedDidShowWithPlacementId:(NSString *)placementId impressionData:(FYBImpressionData *)impressionData { [self reportToAppMetricaWithImpressionData:impressionData placementId:placementId adType:AdTypeRewarded]; } // Implement other delegate methods as needed @end // YourOfferWallDelegate @interface YourOfferWallDelegate : NSObject <OfferWallDelegate> @end @implementation YourOfferWallDelegate - (void)didShowWithPlacementId:(NSString *)placementId { // Assuming reportOfferWallShowToAppMetrica is implemented elsewhere [self reportOfferWallShowToAppMetricaWithPlacementId:placementId ? placementId : @"unknown"]; } // Implement other delegate methods as needed @end
-
Import the required modules:
SwiftObjective-Cimport AppMetricaCore import GoogleMobileAds
#import <AppMetricaCore/AppMetricaCore.h> #import <GoogleMobileAds/GoogleMobileAds.h>
-
Add a helper extension for
GADAdValuePrecision
:SwiftObjective-Cextension GADAdValuePrecision: CustomStringConvertible { public var description: String { switch self { case .precise: return "precise" case .estimated: return "estimated" case .publisherProvided: return "publisher_defined" case .unknown: fallthrough @unknown default: return "unknown" } } }
@interface GADAdValuePrecisionHelper : NSObject + (NSString *)stringFromAdValuePrecision:(GADAdValuePrecision)precision; @end @implementation GADAdValuePrecisionHelper + (NSString *)stringFromAdValuePrecision:(GADAdValuePrecision)precision { switch (precision) { case GADAdValuePrecisionPrecise: return @"precise"; case GADAdValuePrecisionEstimated: return @"estimated"; case GADAdValuePrecisionPublisherProvided: return @"publisher_defined"; case GADAdValuePrecisionUnknown: default: return @"unknown"; } } @end
-
Implement the logic for loading ads and generating impression reports:
SwiftObjective-Cclass ViewController: UIViewController, GADFullScreenContentDelegate { var rewardedAd: GADRewardedAd? func requestRewardedAd() { GADRewardedAd.load( withAdUnitID: "AD_UNIT_ID", request: GADRequest() ) { [weak self] (ad, error) in if let error = error { print("Rewarded ad failed to load with error: \(error.localizedDescription)") return } if let ad = ad { self?.rewardedAd = ad self?.rewardedAd?.paidEventHandler = { adValue in // Extract the impression-level ad revenue data let value = adValue.value let precision = adValue.precision let currencyCode = adValue.currencyCode // Get the ad unit ID let adUnitId = ad.adUnitID // Get additional response info let responseInfo = ad.responseInfo let loadedAdNetworkResponseInfo = responseInfo.loadedAdNetworkResponseInfo let adSourceId = loadedAdNetworkResponseInfo?.adSourceID let adSourceInstanceId = loadedAdNetworkResponseInfo?.adSourceInstanceID let adSourceInstanceName = loadedAdNetworkResponseInfo?.adSourceInstanceName let adSourceName = loadedAdNetworkResponseInfo?.adSourceName let mediationGroupName = responseInfo.extrasDictionary["mediation_group_name"] as? String let mediationABTestName = responseInfo.extrasDictionary["mediation_ab_test_name"] as? String let mediationABTestVariant = responseInfo.extrasDictionary["mediation_ab_test_variant"] as? String // Create AdRevenueInfo object let adRevenueInfo = MutableAdRevenueInfo(adRevenue: value, currency: currencyCode) adRevenueInfo.adType = .rewarded adRevenueInfo.adNetwork = adSourceName ?? "AdMob" adRevenueInfo.adUnitID = adUnitId adRevenueInfo.adPlacementID = adSourceId adRevenueInfo.precision = precision.description // Create payload with additional information var payload: [String: String] = [:] if let adSourceInstanceId = adSourceInstanceId { payload["ad_source_instance_id"] = adSourceInstanceId } if let adSourceInstanceName = adSourceInstanceName { payload["ad_source_instance_name"] = adSourceInstanceName } if let mediationGroupName = mediationGroupName { payload["mediation_group_name"] = mediationGroupName } if let mediationABTestName = mediationABTestName { payload["mediation_ab_test_name"] = mediationABTestName } if let mediationABTestVariant = mediationABTestVariant { payload["mediation_ab_test_variant"] = mediationABTestVariant } adRevenueInfo.payload = payload // Report to AppMetrica AppMetrica.reportAdRevenue(adRevenueInfo) { error in print("Failed to report ad revenue: \(error)") } } } } } }
@interface ViewController : UIViewController <GADFullScreenContentDelegate> @property (nonatomic, strong) GADRewardedAd *rewardedAd; @end @implementation ViewController - (void)requestRewardedAd { [GADRewardedAd loadWithAdUnitID:@"AD_UNIT_ID" request:[GADRequest request] completionHandler:^(GADRewardedAd * _Nullable rewardedAd, NSError * _Nullable error) { if (error) { NSLog(@"Rewarded ad failed to load with error: %@", [error localizedDescription]); return; } self.rewardedAd = rewardedAd; __weak typeof(self) weakSelf = self; // Avoid strong reference cycles self.rewardedAd.paidEventHandler = ^(GADAdValue *adValue) { // Extract the impression-level ad revenue data NSDecimalNumber *value = adValue.value; GADAdValuePrecision precision = adValue.precision; NSString *currencyCode = adValue.currencyCode; // Get the ad unit ID NSString *adUnitId = weakSelf.rewardedAd.adUnitID; // Create AdRevenueInfo object YMMMutableAdRevenueInfo *adRevenueInfo = [[YMMMutableAdRevenueInfo alloc] initWithAdRevenue:value.doubleValue currency:currencyCode]; adRevenueInfo.adType = YMMAdTypeRewarded; adRevenueInfo.adNetwork = @"AdMob"; adRevenueInfo.adUnitID = adUnitId; adRevenueInfo.precision = [NSString stringWithFormat:@"%ld", (long)precision]; // Report to AppMetrica [YMMYandexMetrica reportAdRevenue:adRevenueInfo onFailure:^(NSError *error) { NSLog(@"Failed to report ad revenue: %@", error); }]; }; }]; } @end
Adapt the implementation for other ad formats
-
Replace
GADRewardedAd
with an appropriate class:- Banner:
GADBannerView
- Interstitial:
GADInterstitialAd
- Rewarded interstitial:
GADRewardedInterstitialAd
- Native:
GADNativeAd
- Banner:
-
Change the
adType
when creating anAdRevenueInfo
object:SwiftObjective-CadRevenueInfo.adType = .banner // For banner ads adRevenueInfo.adType = .interstitial // For interstitial and rewarded interstitial ads adRevenueInfo.adType = .native // For native ads adRevenueInfo.adType = .rewarded // For rewarded ads (current example)
// For banner ads adRevenueInfo.adType = AdTypeBanner; // For interstitial and rewarded interstitial ads adRevenueInfo.adType = AdTypeInterstitial; // For native ads adRevenueInfo.adType = AdTypeNative; // For rewarded ads (current example) adRevenueInfo.adType = AdTypeRewarded;
-
Configure the
paidEventHandler
at the appropriate stage of the ad loading process for each format. The implementation of the handler itself remains the same. -
For banner ads, add the
paidEventHandler
directly to theGADBannerView
instance:SwiftObjective-CbannerView.paidEventHandler = { adValue in // Use the same implementation as in the rewarded ad example }
bannerView.paidEventHandler = ^(GADAdValue *adValue) { // Use the same implementation as in the rewarded ad example };
-
For interstitial, rewarded interstitial, and native ads, add the
paidEventHandler
to the ad loading completion handler as shown in the example with rewarded ads.
Note
Don't forget to replace AD_UNIT_ID
with your actual AdMob ad unit ID for each ad format you use.
Ad Revenue data from the ironSource SDK is passed to AppMetrica via the AppMetricaIronSourceAdapter
:
- The adapter must be initialized before activating ironSource.
- AppMetrica should only be activated once during the app lifecycle. It doesn't matter if you do it before or after initializing the adapter.
-
Import the required modules:
SwiftObjective-Cimport AppMetricaCore import AppMetricaIronSourceAdapter import IronSource
#import <AppMetricaCore/AppMetricaCore.h> #import <AppMetricaIronSourceAdapter/AppMetricaIronSourceAdapter.h> import <IronSource/IronSource.h>
-
Initialize the
AppMetricaIronSourceAdapter
before activating ironSource. You can usually do this in the app's initialization code. For example, in theAppDelegate
structure or themain App
forSwiftUI
apps.SwiftObjective-CAppMetricaIronSourceAdapter.shared.initialize()
[[AppMetricaIronSourceAdapter shared] initialize];
-
Configure and activate ironSource and AppMetrica:
SwiftObjective-C// Initialize IronSource IronSource.initWithAppKey("YOUR_IRONSOURCE_APP_KEY", adUnits: [IS_BANNER, IS_INTERSTITIAL, IS_REWARDED_VIDEO]) // Activate AppMetrica guard let configuration = AppMetricaConfiguration(apiKey: "YOUR_APPMETRICA_API_KEY") else { return } AppMetrica.activate(with: configuration)
// Initialize IronSource [IronSource initWithAppKey:@"YOUR_IRONSOURCE_APP_KEY" adUnits:@[IS_BANNER, IS_INTERSTITIAL, IS_REWARDED_VIDEO]]; // Activate AppMetrica AppMetricaConfiguration *configuration = [[AppMetricaConfiguration alloc] initWithApiKey:@"YOUR_APPMETRICA_API_KEY"]; if (configuration == nil) { return; } [AppMetrica activateWithConfiguration:configuration];
Note
The
AppMetricaIronSourceAdapter
automatically passes ad revenue data from ironSource to AppMetrica. You don't need to report impressions or revenue manually.
-
Import the required modules:
SwiftObjective-Cimport AppMetricaCore import AnyThinkSDK import AnyThinkBanner import AnyThinkNative import AnyThinkInterstitial import AnyThinkRewardedVideo import AnyThinkMediaVideo
#import <AppMetricaCore/AppMetricaCore.h> #import <AnyThinkSDK/AnyThinkSDK.h> import <AnyThinkBanner/AnyThinkBanner.h> import <AnyThinkNative/AnyThinkNative.h> import <AnyThinkInterstitial/AnyThinkInterstitial.h> import <AnyThinkRewardedVideo/AnyThinkRewardedVideo.h> import <AnyThinkMediaVideo/AnyThinkMediaVideo.h>
-
Create a function for passing ad revenue data to AppMetrica:
SwiftObjective-Cfunc reportToAppMetrica(_ extra: [AnyHashable: Any], placementID: String, adType: AdType) { guard let revenue = extra[kATADDelegateExtraPublisherRevenueKey] as? Double, let currency = extra[kATADDelegateExtraCurrencyKey] as? String else { print("Missing required revenue information") return } let adRevenueInfo = MutableAdRevenueInfo(adRevenue: NSDecimalNumber(value: revenue), currency: currency) adRevenueInfo.adType = adType adRevenueInfo.adNetwork = extra[kATADDelegateExtraNetworkNameKey] as? String adRevenueInfo.adUnitID = extra[kATADDelegateExtraAdunitIDKey] as? String adRevenueInfo.adPlacementID = placementID adRevenueInfo.precision = extra[kATADDelegateExtraPrecisionKey] as? String // Additional information in payload var payload: [String: String] = [:] if let networkFirmId = extra[kATADDelegateExtraNetworkFirmIdKey] as? Int { payload["network_firm_id"] = String(networkFirmId) } payload["adsource_id"] = extra[kATADDelegateExtraAdSourceIdKey] as? String // Add other relevant information to payload... adRevenueInfo.payload = payload AppMetrica.reportAdRevenue(adRevenueInfo) { error in print("Failed to report ad revenue to AppMetrica: \(error)") } }
- (void)reportToAppMetricaWithExtra:(NSDictionary<AnyHashable, id> *)extra placementID:(NSString *)placementID adType:(AdType)adType { NSNumber *revenue = extra[kATADDelegateExtraPublisherRevenueKey]; NSString *currency = extra[kATADDelegateExtraCurrencyKey]; if (revenue == nil || currency == nil) { NSLog(@"Missing required revenue information"); return; } MutableAdRevenueInfo *adRevenueInfo = [[MutableAdRevenueInfo alloc] initWithAdRevenue:[NSDecimalNumber decimalNumberWithDecimal:[revenue decimalValue]] currency:currency]; adRevenueInfo.adType = adType; adRevenueInfo.adNetwork = extra[kATADDelegateExtraNetworkNameKey]; adRevenueInfo.adUnitID = extra[kATADDelegateExtraAdunitIDKey]; adRevenueInfo.adPlacementID = placementID; adRevenueInfo.precision = extra[kATADDelegateExtraPrecisionKey]; // Additional information in payload NSMutableDictionary<NSString *, NSString *> *payload = [NSMutableDictionary new]; NSNumber *networkFirmId = extra[kATADDelegateExtraNetworkFirmIdKey]; if (networkFirmId != nil) { payload[@"network_firm_id"] = [networkFirmId stringValue]; } payload[@"adsource_id"] = extra[kATADDelegateExtraAdSourceIdKey]; // Add other relevant information to payload... adRevenueInfo.payload = payload; [AppMetrica reportAdRevenue:adRevenueInfo completion:^(NSError * _Nullable error) { if (error) { NSLog(@"Failed to report ad revenue to AppMetrica: %@", error); } }]; }
-
Implement the corresponding delegate methods for each ad format:
SwiftObjective-Cclass YourBannerDelegate: NSObject, ATBannerDelegate { func bannerView(_ bannerView: ATBannerView, didShowAdWithPlacementID placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .banner) } // Implement other delegate methods as needed } class YourNativeDelegate: NSObject, ATNativeADDelegate { func didShowNativeAd(in adView: ATNativeADView, placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .native) } // Implement other delegate methods as needed } class YourInterstitialDelegate: NSObject, ATInterstitialDelegate { func interstitialDidShow(forPlacementID placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .interstitial) } // Implement other delegate methods as needed } class YourRewardedVideoDelegate: NSObject, ATRewardedVideoDelegate { func rewardedVideoDidShow(forPlacementID placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .rewarded) } // Implement other delegate methods as needed } class YourSplashDelegate: NSObject, ATSplashDelegate { func splashDidShow(forPlacementID placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .other) } // Implement other delegate methods as needed } class YourMediaVideoDelegate: NSObject, ATMediaVideoDelegate { func mediaVideoDidStartPlaying(forPlacementID placementID: String, extra: [AnyHashable : Any]) { reportToAppMetrica(extra, placementID: placementID, adType: .other) media video } // Implement other delegate methods as needed }
#import <AppMetricaCore/AppMetricaCore.h> #import <AnyThinkSDK/AnyThinkSDK.h> import <AnyThinkBanner/AnyThinkBanner.h> import <AnyThinkNative/AnyThinkNative.h> import <AnyThinkInterstitial/AnyThinkInterstitial.h> import <AnyThinkRewardedVideo/AnyThinkRewardedVideo.h> import <AnyThinkMediaVideo/AnyThinkMediaVideo.h>
-
Initialize the
MutableAdRevenueInfo
instance. -
Send the
MutableAdRevenueInfo
instance to the main API key using the+reportAdRevenue:onFailure:
method of theAppMetrica
class.SwiftObjective-CAppMetrica.report(adRevenue: adRevenueInfo) { error in print("AdRevenue error: \(error)") }
[AMAAppMetrica reportAdRevenue:[adRevenueInfo copy] onFailure:^(NSError *error) { NSLog(@"AdRevenue error: %@", error); }];
Step 3. Make sure that the ad revenue data is included in the reports
-
View ads in the app.
-
Make sure that the Revenue report shows the same number of ad revenue events as the number of ad views.
Setting the session timeout
By default, the session timeout is 10 seconds. This is the minimum acceptable value for the sessionTimeout
property.
To change the timeout length, pass the value in seconds to the sessionTimeout
property of the library configuration AppMetricaConfiguration
.
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Setting the session timeout.
configuration.sessionTimeout = 15
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
To change the timeout length, pass the value in seconds to the sessionTimeout
property of the library configuration AMAAppMetricaConfiguration
.
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Setting the session timeout.
configuration.sessionTimeout = 15;
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
Setting the app version
By default, the app version is set in the app configuration file Info.plist (CFBundleShortVersionString
).
To specify the app version from the code, pass it to the appVersion
property of the AppMetricaConfiguration
configuration.
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Setting the app version.
configuration.appVersion = "1.13.2"
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
To specify the app version from the code, pass it to the appVersion
property of the AMAAppMetricaConfiguration
configuration.
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Setting the app version.
configuration.appVersion = @"1.13.2";
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
Tracking app opens using deeplinks
Warning
Starting with version 4.0 of the AppMetrica SDK for iOS, app openings via deeplinks are tracked automatically. For other versions, set up tracking manually:
- iOS AppMetrica SDK version below 4.0. Setting up deeplink tracking for UIApplicationDelegate.
- Setting up deeplink tracking for UISceneDelegate (AppMetrica doesn't track such app openings automatically).
You need to track app openings to correctly track remarketing campaigns.
Note
To work with Universal Links, configure them for your application.
UISceneDelegate
To manually track app openings via universal links or deeplinks, in UISceneDelegate
, add the following code to the scene:willConnectToSession:options:
method:
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session
options:(UISceneConnectionOptions *)connectionOptions
{
//Universal Link
NSUserActivity *userActivity = [[connectionOptions.userActivities allObjects] firstObject];
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
[AMAAppMetrica trackOpeningURL:context.URL];
}
else {
//Deeplink
UIOpenURLContext *context = [[connectionOptions.URLContexts allObjects] firstObject];
if (context != nil) {
[AMAAppMetrica trackOpeningURL:context.URL];
}
}
}
To manually track app openings via universal links or deeplinks in a running app, use the following code:
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
{
NSURL *url = userActivity.webpageURL;
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
[AMAAppMetrica trackOpeningURL:context.URL];
}
}
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
UIOpenURLContext *context = [[URLContexts allObjects] firstObject];
if (context != nil) {
[AMAAppMetrica trackOpeningURL:context.URL];
}
}
To manually track app openings via universal links or deeplinks, in UISceneDelegate
, add the following code to the scene(_:willConnectTo:options:)
method:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Universal Link
if let userActivity = connectionOptions.userActivities.first {
if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL {
AppMetrica.trackOpeningURL(url)
}
}
// Deep Link
if let context = connectionOptions.urlContexts.first {
AppMetrica.trackOpeningURL(context.url)
}
}
To manually track app openings via universal links or deeplinks in a running app, use the following code:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else { return }
AppMetrica.trackOpeningURL(url)
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let context = URLContexts.first else { return }
AppMetrica.trackOpeningURL(context.url)
}
UIApplicationDelegate
Warning
Manual setup of tracking with UIApplicationDelegate is relevant for iOS AppMetrica SDK versions below 4.0.
To manually track app openings via universal links or deeplinks, use the +trackOpeningURL:
method of the AMAAppMetrica
class.
To manually track app openings using deeplinks or deeplink handling in a running app, use UIApplicationDelegate
and add the following modifications:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
[AMAAppMetrica trackOpeningURL:url];
return YES;
}
// Delegate for tracking Universal links.
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
[AMAAppMetrica trackOpeningURL:userActivity.webpageURL];
}
return YES;
}
To manually track app openings via universal links or deeplinks, use the +trackOpeningURL:
method of the AMAAppMetrica
class.
To manually track app openings using deeplinks or deeplink handling in a running app, use UIApplicationDelegate
and add the following modifications:
func application(_ application: UIApplication, openURL url: URL, sourceApplication: String?, annotation: AnyObject) -> Bool {
AppMetrica.trackOpeningURL(url)
return true
}
// Delegate for tracking Universal links.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
if let url = userActivity.webpageURL {
AppMetrica.trackOpeningURL(url)
}
}
return true
}
See also How to create a remarketing campaign in AppMetrica.
Tracking new users
By default, the user is counted as a new user when the app is opened for the first time. If you connect the AppMetrica SDK to an app that already has active users, you can set up tracking new and old users to get correct statistics.
To do this, initialize the AppMetrica SDK using the AMAAppMetricaConfiguration
extended startup configuration.
BOOL isFirstLaunch = NO;
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Implement the logic for detecting whether the app is starting for the first time.
// For example, you can check for files (settings, databases, and so on),
// which the app creates on its first launch.
if (conditions) {
isFirstLaunch = YES;
}
configuration.handleFirstActivationAsUpdate = !isFirstLaunch;
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
To do this, initialize the AppMetrica SDK using the AppMetricaConfiguration
extended startup configuration.
var isFirstLaunch = false
// Creating an extended library configuration.
guard let configuration = AppMetricaConfiguration(apiKey: "API key") else {
print("AppMetricaConfiguration initialization failed.")
return // or return someDefaultValue or throw someError
}
// Implement the logic for detecting whether the app is starting for the first time.
// For example, you can check for files (settings, databases, and so on),
// which the app creates on its first launch.
if conditions {
isFirstLaunch = true
}
configuration.handleFirstActivationAsUpdate = !isFirstLaunch
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
Disabling and enabling sending statistics
If you need confirmation from the user before sending statistical data, you should initialize the library with the disabled sending option.
To do this, set the NO
value for the dataSendingEnabled
property of the AMAAppMetricaConfiguration
.
// Creating an extended library configuration.
AMAAppMetricaConfiguration *configuration = [[AMAAppMetricaConfiguration alloc] initWithAPIKey:@"API key"];
// Disabling sending statistics.
configuration.dataSendingEnabled = NO;
// Initializing the AppMetrica SDK.
[AMAAppMetrica activateWithConfiguration:configuration];
After the user has consented to sending statistics (for example, in the app settings or in the agreement on the first start of the app), you should enable sending using the +setDataSendingEnabled:
method of the AMAAppMetrica
class.
// Checking the status of the boolean variable. It shows the user confirmation.
if (flag) {
// Enabling sending statistics.
[AMAAppMetrica setDataSendingEnabled:YES];
}
To do this, set the false
value for the dataSendingEnabled
property of the AppMetricaConfiguration
.
// Creating an extended library configuration.
if let configuration = AppMetricaConfiguration(apiKey: "API key") {
// Disabling sending statistics.
configuration.dataSendingEnabled = false
// Initializing the AppMetrica SDK.
AppMetrica.activate(with: configuration)
}
After the user has consented to sending statistics (for example, in the app settings or in the agreement on the first start of the app), you should enable sending using the setDataSendingEnabled(_:)
method of the AppMetrica
class.
// Checking the status of the boolean variable. It shows the user confirmation.
if flag {
// Enabling sending statistics.
AppMetrica.setDataSendingEnabled(true);
}
Alert example
You can use any text to inform users of statistics collection. For example:
This app uses the AppMetrica analytical service provided by YANDEX LLC, ulitsa Lva Tolstogo 16, Moscow, Russia 119021 (hereinafter referred to as Yandex) based on the Terms of Use.
AppMetrica analyzes app usage data, including the device it is running on, the installation source, calculates conversion, collects statistics of your activity for product analytics, ad campaign analysis, and optimization, as well as for troubleshooting. Information collected in this way cannot identify you.
Depersonalized information about your use of this app collected by AppMetrica tools will be transferred to Yandex and stored on Yandex’s server in the EU and the Russian Federation. Yandex will process this information to assess how you use the app, compile reports for us on our app operation, and provide other services.
Getting AppMetrica SDK IDs
To get AppMetrica SDK IDs (DeviceId
, DeviceIdHash
, UUID
), use the requestStartupIdentifiersWithKeys()
/ requestStartupIdentifiers()
method. To get the appmetrica_device_id
, make sure to request the DeviceIdHash
.
AMAIdentifiersCompletionBlock block = ^(NSDictionary<AMAStartupKey,id> * _Nullable identifiers, NSError * _Nullable error) {
if (identifiers[kAMADeviceIDHashKey] != nil) {
NSLog(@"deviceIDHash = %@", identifiers[kAMADeviceIDHashKey]);
}
if (identifiers[kAMADeviceIDKey] != nil) {
NSLog(@"deviceID = %@", identifiers[kAMADeviceIDKey]);
}
if (identifiers[kAMAUUIDKey] != nil) {
NSLog(@"uuid = %@", identifiers[kAMAUUIDKey]);
}
};
[AMAAppMetrica requestStartupIdentifiersWithKeys:@[kAMADeviceIDHashKey, kAMADeviceIDKey, kAMAUUIDKey] completionQueue:nil completionBlock:block];
// Specifying the keys for which we need to get identifiers
let keys: [StartupKey] = [StartupKey.deviceIDKey, StartupKey.deviceIDHashKey, StartupKey.uuidKey]
// Specifying the queue on which the completion handler will be executed (for example, the main thread)
let queue = DispatchQueue.main
// Requesting IDs
AppMetrica.requestStartupIdentifiers(for: keys, on: queue) { identifiers, error in
if let error = error {
print("An error has occurred: \(error.localizedDescription)")
} else if let identifiers = identifiers {
// Processing the received IDs
if let deviceIDHash = identifiers[StartupKey.deviceIDHashKey] as? String {
print("AppMetrica deviceIDHash: \(deviceIDHash)")
}
if let deviceID = identifiers[StartupKey.deviceIDKey] as? String {
print("AppMetrica deviceID: \(deviceID)")
}
if let uuid = identifiers[StartupKey.uuidKey] as? String {
print("AppMetrica uuid: \(uuid)")
}
}
}
If you didn't find the answer you were looking for, you can use the feedback form to submit your question. Please describe the problem in as much detail as possible. Attach a screenshot if possible.
An ad campaign aimed at getting users to come back to an app they previously installed. For more information, see Creating a remarketing tracker.