> [!NOTE]
> **Note:** This guide describes the old implementation of Google Tag Manager in Android applications. New users should use [Tag Manager + Firebase](https://developers.google.com/tag-platform/tag-manager/android/v5) to implement Google Tag Manager in their iOS applications.

This developer guide describes how to implement Google Tag Manager in a
mobile application.

## Introduction

Google Tag Manager enables developers to change configuration
values in their mobile applications using the Google Tag Manager
interface without having to rebuild and resubmit application binaries to app
marketplaces.

This is useful for managing any configuration values
or flags in your application that you may need to change in the future,
including:

- Various UI settings and display strings
- Sizes, locations, or types of ads served in your application
- Game settings

Configuration values may also be evaluated at runtime using rules,
enabling dynamic configurations such as:

- Using screen size to determine ad banner size
- Using language and location to configure UI elements

Google TagManager also enables the dynamic implementation of tracking tags
and pixels in applications. Developers can push important events into a data
layer and decide later which tracking tags or pixels should be fired.
TagManager supports the following tags:

- Google Mobile App Analytics
- Custom Function Call tag

## Before you Begin

Before using this getting started guide, you'll need the following:

- A [Google Tag Manager Account](https://www.google.com/tagmanager)
- A new Tag Manager [container and value collection macro](https://support.google.com/tagmanager/answer/3127354)
- A mobile application for iOS in which to implement Google Tag Manager
- The [Google Analytics Services SDK](https://developers.google.com/analytics/devguides/collection/ios/resources), which contains the Tag Manager library.

If you're new to Google Tag Manager, we recommend that you
[learn more about containers, macros, and rules (Help Center)](https://support.google.com/tagmanager/answer/2574305/) before continuing this guide.

## Getting Started

This section will guide developers through a typical Tag Manager workflow:

1. [Add the Google Tag Manager SDK to your project](https://developers.google.com/tag-platform/tag-manager/ios/v3#add-sdk)
2. [Set Default Container Values](https://developers.google.com/tag-platform/tag-manager/ios/v3#set-default)
3. [Open the Container](https://developers.google.com/tag-platform/tag-manager/ios/v3#open-container)
4. [Get Configuration Values from the Container](https://developers.google.com/tag-platform/tag-manager/ios/v3#get-values)
5. [Push Events to the DataLayer](https://developers.google.com/tag-platform/tag-manager/ios/v3#push-datalayer)
6. [Preview \& Publish the Container](https://developers.google.com/tag-platform/tag-manager/ios/v3#preview-publish)

## 1. Adding the Google Tag Manager SDK to Your Project

Before using the Google Tag Manager SDK, you'll need to add
`libGoogleAnalyticsServices.a`
and the Google Tag Manager (GTM) header files from the `Library`
directory of the SDK package to your project.

Next, add the following to your application target's linked libraries if they
are not already present:

- `CoreData.framework`
- `SystemConfiguration.framework`
- `libz.dylib`
- `libsqlite3.dylib`
- `libGoogleAnalyticsServices.a`

If you would like your application to access the identifier for
advertisers (IDFA) and tracking flag provided by that framework through the
Google Tag Manager SDK macros, you'll also need to link these additional libraries:

- `libAdIdAccess.a`
- `AdSupport.framework`

> [!NOTE]
> **Note** : depending on your build settings, the linker flag `-force_load /path/to/libAdIdAccess.a` may be required.

## 2. Adding a Default Container File to your Project

> [!NOTE]
> **Note** : If you have not yet [configured your container in the Google Tag Manager web interface](https://support.google.com/tagmanager/answer/3127354), return to this step once you've done so.

Google Tag Manager uses a default container on the first run of your application. The default
container will be used until the app is able to retrieve a fresh container over the
network.

To download and add a default container binary to your application, follow these steps:

1. Sign in to the Google Tag Manager web interface.
2. Select the **Version** of the container you'd like to download.
3. Click the **Download** button to retrieve the container binary.
4. Add the binary file to your project's root directory and to the "Supporting Files" folder in your project.

The default filename should be the container ID (for example `GTM-1234`). Once you've
downloaded the binary file, be sure to remove the version suffix from the filename
to ensure you follow the correct naming convention.

Although using the binary file is recommended, if your container does not contain rules or tags,
you may choose to use a property list or JSON file instead. The file should be located in the main bundle and should follow
this naming convention: `<Container_ID>.<plist|json>`.
For example, if your container ID is `GTM-1234`, you could specify
your default container values in a property list file named
`GTM-1234.plist`.

> [!NOTE]
> **Note**: if both a property list and JSON default container are present in the main bundle, the SDK will use the Property List as the default container.

## 3. Opening a Container

Before retrieving values from a container, your application needs to open
the container. Opening a container will load it from disk (if available), or
will request it from the network (if needed).

The easiest way to open a container on iOS is by using
`openContainerWithId:tagManager:openType:timeout:notifier:`, as in the following example:

```
// MyAppDelegate.h
// This example assumes this file is using ARC.
#import <UIKit/UIKit.h>

@class TAGManager;
@class TAGContainer;

@interface MyAppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) TAGManager *tagManager;
@property (nonatomic, strong) TAGContainer *container;

@end


// MyAppDelegate.m
// This example assumes this file is using ARC.
#import "MyAppDelegate.h"
#import "TAGContainer.h"
#import "TAGContainerOpener.h"
#import "TAGManager.h"

@interface MyAppDelegate ()<TAGContainerOpenerNotifier>
@end

@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.tagManager = [TAGManager instance];

  // Optional: Change the LogLevel to Verbose to enable logging at VERBOSE and higher levels.
  [self.tagManager.logger setLogLevel:kTAGLoggerLogLevelVerbose];

  /*
   * Opens a container.
   *
   * @param containerId The ID of the container to load.
   * @param tagManager The TAGManager instance for getting the container.
   * @param openType The choice of how to open the container.
   * @param timeout The timeout period (default is 2.0 seconds).
   * @param notifier The notifier to inform on container load events.
   */
  [TAGContainerOpener openContainerWithId:@"GTM-XXXX"   // Update with your Container ID.
                               tagManager:self.tagManager
                                 openType:kTAGOpenTypePreferFresh
                                  timeout:nil
                                 notifier:self];

  // Method calls that don't need the container.

  return YES;
}

// TAGContainerOpenerNotifier callback.
- (void)containerAvailable:(TAGContainer *)container {
  // Note that containerAvailable may be called on any thread, so you may need to dispatch back to
  // your main thread.
  dispatch_async(dispatch_get_main_queue(), ^{
    self.container = container;
  });
}

// The rest of your app delegate implementation.
```

> [!NOTE]
> **Note**: If your application depends on configuration values from the container, you should display a splash screen or other intermediate view until the container has loaded. One way to do this is to move the container loading code into your root view controller. Your root view controller can present a modal view while the container loads.

## 4. Getting Configuration Values from the Container

Once the container is open, configuration values may be retrieved using
the `<type>ForKey:` methods:

```
// Retrieving a configuration value from a Tag Manager Container.

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
TAGContainer *container = appDelegate.container;

// Get the configuration value by key.
NSString *title = [container stringForKey:@"title_string"];
```

Requests made with a non-existent key will return a default value appropriate
to the type requested:

```
// Empty keys will return a default value depending on the type requested.

// Key does not exist. An empty string is returned.
NSString subtitle = [container stringForKey:@"Non-existent-key"];
[subtitle isEqualToString:@""]; // Evaluates to true.
```

## 5. Pushing Values to the DataLayer

The DataLayer is a map that enables runtime information about your app, such as touch
events or screen views, to become available to Tag Manager macros and tags in a
container.

For example, by pushing information about screen views into the DataLayer map,
you can set up tags in the Tag Manager web interface to fire conversion pixels
and tracking calls in response to those screenviews without needing to hard
code them into your app.

Events are pushed to the DataLayer using `push:`

```
//
//  ViewController.m
//  Pushing an openScreen event with a screen name into the data layer.
//

#import "MyAppDelegate.h"
#import "TAGDataLayer.h"
#import "ViewController.h"

@implementation ViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // The container should have already been opened, otherwise events pushed to
    // the data layer will not fire tags in that container.
    TAGDataLayer *dataLayer = [TAGManager instance].dataLayer;

    [dataLayer push:@{@"event": @"openScreen", @"screenName": @"Home Screen"}];
}

// Rest of the ViewController implementation

@end
```

In the web interface, you can now create tags (like Google Analytics tags)
to fire for each screen view by creating this rule:
{{ event }} equals "openScreen". To pass the screen name
to one of these tags, create a data layer macro that references the "screenName"
key in the data layer. You can also create a tag
(like a Google Ads conversion pixel) to fire only for specific screen views, by
creating a rule where {{ event }} equals "openScreen"
\&\& {{ screenName }} equals "ConfirmationScreen".

> [!NOTE]
> **Note**: DataLayer event values and keys should be used as consistently as possible, so that in this example, all screen views use "openScreen" as their event value, and "screenName" as their screen name key. This makes accessing the DataLayer and creating additional tags in the future straightforward.

## 6. Previewing \& Publishing a Container

Macro values will always correspond to the current published version.
Before publishing the latest version of a container, you can preview
your draft container.

To preview a container, generate a preview URL in the Google
Tag Manager web interface by selecting the version of the container
you'd like to preview, and then selecting `Preview`. Save
this preview URL as you'll need it in later steps.
![Preview URLs are available in the preview window of the Tag
Manager web interface](https://developers.google.com/static/tag-platform/tag-manager/images/android/v3/preview.png) **Figure 1:**Getting a preview URL from the Tag Manager web interface.

To enable container previews, you must add code to your app
delegate implementation file and define the Google Tag Manager preview URL
scheme in your project's property list.

First, add the following bolded code snippets to your app delegate file:

```
@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  self.tagManager = [TAGManager instance];
  
  // Add the code in bold below to preview a Google Tag Manager container.
  // IMPORTANT: This code must be called before the container is opened.
  NSURL *url = [launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
  if (url != nil) {
    [self.tagManager previewWithUrl:url];
  }
  
  id<TAGContainerFuture> future =
      [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                   tagManager:self.tagManager
                                     openType:kTAGOpenTypePreferNonDefault
                                      timeout:nil];

  // The rest of your method implementation.

  self.container = [future get];

  return YES;
}


// Add the code in bold below preview a Google Tag Manager container.
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {

  if ([self.tagManager previewWithUrl:url]) {
    return YES;
  }

  // Code to handle other urls.
  return NO;
}
```

Next, register the following URL identifier and URL scheme under the
URL types key of your application's property list file:

```
URL identifier: your.package_name
URL scheme: tagmanager.c.your.package.name
```
![Register the tag manager preview URL scheme in your application's
property list file.](https://developers.google.com/static/tag-manager/img/ios/plist.png) **Figure 3:**Adding the Tag Manager preview URL scheme to your application's property list file.

> [!NOTE]
> **Note** : *your.package.name* needs to match the name of the app used to generate the preview URL (Figure 1).

Open the link on an emulator or physical device to
preview the draft container in your app.

When you're ready to make your draft configuration values available to your
application, [publish the container](https://support.google.com/tagmanager/answer/3127354).

## Advanced Configuration

Google Tag Manager for Mobile has a number of advanced configuration
options that allow you to select values based on runtime conditions using
rules, manually refresh the container, and get additional options for opening
containers. The following sections outline several of the most common advanced
configurations.

## Advanced Options for Opening Containers

The Google Tag Manager SDK provides several methods for opening
containers that can give you more control over the loading process:

### openContainerById:callback:

`openContainerById:callback:` is the lowest level and most flexible API for opening a
container. It returns immediately with a default container and
also asynchronously loads a container from disk or the network if no saved
container exists, or if the saved container is not fresh (\> 12 hours old).

```
@interface ContainerCallback : NSObject<TAGContainerCallback>

@end

@implementation ContainerCallback

/**
 * Called before the refresh is about to begin.
 *
 * @param container The container being refreshed.
 * @param refreshType The type of refresh which is starting.
 */
- (void)containerRefreshBegin:(TAGContainer *)container
                  refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container refresh is beginning.
}

/**
 * Called when a refresh has successfully completed for the given refresh type.
 *
 * @param container The container being refreshed.
 * @param refreshType The type of refresh which completed successfully.
 */
- (void)containerRefreshSuccess:(TAGContainer *)container
                    refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container is available.
}

/**
 * Called when a refresh has failed to complete for the given refresh type.
 *
 * @param container The container being refreshed.
 * @param failure The reason for the refresh failure.
 * @param refreshType The type of refresh which failed.
 */
- (void)containerRefreshFailure:(TAGContainer *)container
                        failure:(TAGContainerCallbackRefreshFailure)failure
                    refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container request has failed.
}
@end
```

Throughout the loading process, `openContainerById:callback:` issues
several lifecycle callbacks so that your code can find out when the
loading request begins, whether and why it fails or succeeds, and whether
the container was ultimately loaded from disk or network.

Unless it is acceptable for your application to use the default values,
you will need to use these callbacks to know when a saved or network
container has loaded. Note that you will be unable to load a saved or
network container if this is the first time the app is run and there's no
network connection.

`openContainerById:callback:` passes the following `enum`
values as arguments to these callbacks:

#### RefreshType

| Value | Description |
|---|---|
| `kTAGContainerCallbackRefreshTypeSaved` | The refresh request is loading a locally saved container. |
| `kTAGContainerCallbackRefreshTypeNetwork` | The refresh request is loading a container over the network. |

#### RefreshFailure

| Value | Description |
|---|---|
| `kTAGContainerCallbackRefreshFailureNoSavedContainer` | There is no saved container available. |
| `kTAGContainerCallbackRefreshFailureIoError` | An I/O error prevented refreshing the container. |
| `kTAGContainerCallbackRefreshFailureNoNetwork` | There is no network connection available. |
| `kTAGContainerCallbackRefreshFailureNetworkError` | A network error has occurred. |
| `kTAGContainerCallbackRefreshFailureServerError` | An error on the server has occurred. |
| `kTAGContainerCallbackRefreshFailureUnknownError` | An error that can't be categorized has occurred. |

### Methods for Opening Non-Default and Fresh Containers

`TAGContainerOpener` wraps `openContainerById:callback:`
and provides two convenience methods for opening containers:
`openContainerWithId:tagManager:openType:timeout:notifier:` and
`openContainerWithId:tagManager:openType:timeout:`.

Each of these methods takes an enumeration requesting either a non-default or
fresh container.

`kTAGOpenTypePreferNonDefault` is recommended for most applications and
attempts to return the first available non-default container within a given
timeout period, either from disk or network, even if that container is greater
than 12 hours old. If it returns a stale saved container, it will also make an
asynchronous network request for a fresh one.
When using `kTAGOpenTypePreferNonDefault`, a default
container will be returned if no other container is available, or if the timeout period is
exceeded.

`kTAGOpenTypePreferFresh` attempts to return a fresh container from
either disk or network within the given timeout period.
It returns a saved container if a network
connection is unavailable and/or the timeout period is exceeded.

It is not recommended to use `kTAGOpenTypePreferFresh`
in places where a longer request time may noticeably affect user experience,
such as with UI flags or display strings. You may also use

`TAGContainer::refresh` at any time
to force a network container request.

Both of these convenience methods are non-blocking.
`openContainerWithId:tagManager:openType:timeout:` returns a
`TAGContainerFuture` object, whose `get` method returns a
`TAGContainer` as soon as it has loaded (but that will block until then).
The `openContainerWithId:tagManager:openType:timeout:notifier:` method takes a single callback,
called when the container is available.
Both methods have a default timeout period of

`2.0` seconds.

## Evaluating Macros at Runtime using Rules

Containers can evaluate values at runtime using rules. Rules may be based
on criteria like device language, platform, or any other macro value. For
example, rules can be used to select a localized display string based on the
language of the device at runtime. This can be configured by using the
following rule:
![A rule is used to select display strings based on device language at
runtime: language equals es. This rule uses the pre-defined language
macro and a two character ISO 639-1 language code.](https://developers.google.com/static/tag-platform/tag-manager/images/android/v3/rules.png) **Figure 1:**Adding a rule to enable a value collection macro only for devices configured to use the Spanish language.

You can then create value collection macros for each language, and add this
rule to each macro, inserting the appropriate language code. When this container
is published, your application will be able to display localized display
strings, depending on the language of the user's device at runtime.

Note that if your default container needs rules, you must use a
[binary container file](https://developers.google.com/tag-platform/tag-manager/ios/v3#binary-container) as your default
container.

[Learn more about configuring rules (Help Center).](https://support.google.com/tagmanager/answer/2644396/)

### Binary Default Container Files

Default containers that need rules should use a binary container file
instead of a [property list file or JSON
file](https://developers.google.com/tag-platform/tag-manager/ios/v3#set-default) as the default container. Binary containers offer support for determining
macro values at runtime with Google Tag Manager rules, whereas
property list or JSON
files don't.

Binary container files may be downloaded from the Google Tag Manager web
interface and should be added to your main application bundle following this naming convention:
`GTM-XXXX`, where the filename represents your
container ID.

In cases where a property list file and/or JSON file
as well as a binary container file are present, the SDK will use the binary container
file as the default container.

## Using Function Call Macros

Function Call Macros are macros that are set to the return value of
a specified function in your application. Function Call Macros can be used to
incorporate runtime values with your Google Tag Manager rules, such as
determine at runtime which price to display to a user based on the configured
language and currency of a device.

To configure a function call macro:

1. Define the function call macro in the Google Tag Manager web interface. Arguments may optionally be configured as key-value pairs.
2. Define a handler that implements the `TAGFunctionCallMacroHandler` protocol:

   ```
   // MyFunctionCallMacroHandler.h
   #import "TAGContainer.h"

   // The function name field of the macro, as defined in the Google Tag Manager
   // web interface.
   extern NSString *const kMyMacroFunctionName;

   @interface MyFunctionCallMacroHandler : NSObject<TAGFunctionCallMacroHandler>

   @end


   // MyFunctionCallMacroHandler.m
   #import "MyFunctionCallMacroHandler.h"

   // Corresponds to the function name field in the Google Tag Manager interface.
   NSString *const kMyMacroFunctionName = @"myConfiguredFunctionName";

   @implementation MacroHandler

   - (id)valueForMacro:(NSString *)functionName parameters:(NSDictionary *)parameters {

     if ([functionName isEqualToString:kMyMacroFunctionName]) {
       // Process and return the calculated value of this macro accordingly.
       return macro_value;
     }
     return nil;
   }

   @end
   ```
3. Register the handler using TAGContainer::registerFunctionCallMacroHandler:forMacro: and the function name specified in the Google Tag Manager interface:

   ```
   //
   // MyAppDelegate.h
   //
   #import <UIKit/UIKit.h>

   @interface MyAppDelegate : UIResponder <UIApplicationDelegate>

   @end


   //
   // MyAppDelegate.m
   //
   #import "MyAppDelegate.h"
   #import "MyFunctionCallMacroHandler.h"
   #import "TAGContainer.h"
   #import "TAGContainerOpener.h"
   #import "TAGManager.h"

   @implementation MyAppDelegate

   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
   {
     // Open the container.
     id<TAGContainerFuture> future =
         [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                      tagManager:[TAGManager instance]
                                        openType:kTAGOpenTypePreferNonDefault
                                         timeout:nil];

     // Method calls that don't need the container.

     self.container = [future get];

     // Register a function call macro handler using the macro name defined
     // in the Google Tag Manager web interface.
     [self.container registerFunctionCallMacroHandler:[[MyFunctionCallMacroHandler alloc] init]
                                             forMacro:kMyMacroFunctionName];
   }

   @end
   ```

## Using Function Call Tags

Function Call Tags enable pre-registered functions to be executed whenever
an event is pushed into the data layer and the tag rules
evaluate to `true`.

To configure a function call tag:

1. Define the function call tag in the Google Tag Manager web interface. Arguments may optionally be configured as key-value pairs.
2. Implement the `TAGFunctionCallTagHandler` protocol:

   ```
   //
   // MyFunctionCallTagHandler.h
   //

   #import "TAGContainer.h"

   extern NSString *const kMyTagFunctionName;

   @interface MyFunctionCallTagHandler : NSObject<TAGFunctionCallTagHandler>

   @end


   //
   // MyFunctionCallTagHandler.m
   //

   // Corresponds to the function name field in the Google Tag Manager interface.
   NSString *const kMyTagFunctionName = @"myConfiguredFunctionName";

   @implementation MyFunctionCallTagHandler

   /**
    * This method will be called when any custom tag's rule(s) evaluate to true and
    * should check the functionName and process accordingly.
    *
    * @param functionName corresponds to the function name field, not tag
    *     name field, defined in the Google Tag Manager web interface.
    * @param parameters An optional map of parameters as defined in the Google
    *     Tag Manager web interface.
    */
   - (void)execute:(NSString *)functionName parameters:(NSDictionary *)parameters {

     if ([functionName isEqualToString:kMyTagFunctionName]) {
       // Process accordingly.
     }
   }
   @end
   ```
3. Register the function call tag handler using the tag name configured in the Google Tag Manager web interface:

   ```
   //
   // MyAppDelegate.h
   //
   #import <UIKit/UIKit.h>

   @interface MyAppDelegate : UIResponder <UIApplicationDelegate>

   @end


   //
   // MyAppDelegate.m
   //
   #import "MyAppDelegate.h"
   #import "MyFunctionCallTagHandler.h"
   #import "TAGContainer.h"
   #import "TAGContainerOpener.h"
   #import "TAGManager.h"

   @implementation MyAppDelegate

   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

     // Open the container.
     id<TAGContainerFuture> future =
         [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                      tagManager:[TAGManager instance]
                                        openType:kTAGOpenTypePreferNonDefault
                                         timeout:nil];

     // Method calls that don't need the container.

     self.container = [future get];

     // Register a function call tag handler using the function name of the tag as
     // defined in the Google Tag Manager web interface.
     [self.container registerFunctionCallTagHandler:[[MyFunctionCallTagHandler alloc] init]
                                             forTag:kMyTagFunctionName];
   }
   @end
   ```

## Setting a Custom Refresh Period

The Google Tag Manager SDK will attempt to retrieve
a fresh container if the current container age exceeds 12 hours. To set a
custom container refresh period, use

`NSTimer`, as in the
following example:

```
- (void)refreshContainer:(NSTimer *)timer {
  [self.container refresh];
}

self.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:<refresh_interval>
                                                     target:self
                                                   selector:@selector(refreshContainer:)
                                                   userInfo:nil
                                                    repeats:YES];
```

## Debugging with Logger

The Google Tag Manager SDK prints errors and warnings to logs by default.
Enabling more verbose logging can be helpful for debugging and is possible by
implementing your own `Logger`, as in this example:

```
// MyAppDelegate.h
// This example assumes this file is using ARC.
// This Logger class will print out not just errors and warnings (as the default
// logger does), but also info, debug, and verbose messages.
@interface MyLogger: NSObject<TAGLogger>
@end

@implementation MyLogger
- (void)error:(NSString *)message {
  NSLog(@"Error: %@", message);
}

- (void)warning:(NSString *)message {
  NSLog(@"Warning: %@", message);
}

- (void)info:(NSString *)message {
  NSLog(@"Info: %@", message);
}

- (void)debug:(NSString *)message {
  NSLog(@"Debug: %@", message);
}

- (void)verbose:(NSString *)message {
  NSLog(@"Verbose: %@", message);
}
@end

// MyAppDelegate.m
// This example assumes this file is using ARC.
@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.tagManager = [TAGManager instance];
  
  self.tagManager.logger = [[MyLogger alloc] init];
  
  // Rest of Tag Manager and method implementation.
  return YES;
}
// Rest of app delegate implementation.
@end
```

Or, you can set the LogLevel of the existing Logger by using


`TagManager::logger::setLogLevel`,
as in this example:

```
// Change the LogLevel to INFO to enable logging at INFO and higher levels.
self.tagManager = [TAGManager instance];
[self.tagManager.logger setLogLevel:kTAGLoggerLogLevelInfo];
```