{"id":138699,"date":"2025-03-17T03:15:28","date_gmt":"2025-03-17T03:15:28","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/setup-google-tag-manager-ios-with-swift\/"},"modified":"2025-03-17T03:15:28","modified_gmt":"2025-03-17T03:15:28","slug":"setup-google-tag-manager-ios-with-swift","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=138699","title":{"rendered":"Setup Google Tag Manager iOS With Swift"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>I\u2019ve been meaning to write about <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> for <strong>mobile apps<\/strong> for such a long time. Finally, I have some great use cases to share, as well as some useful examples for implementing <a href=\"https:\/\/developers.google.com\/tag-manager\/ios\/v3\/\">GTM for iOS<\/a>. That\u2019s right, this is an <strong>iOS<\/strong> guide, and, to be more specific, geared towards a successful <strong>Swift<\/strong> implementation.<\/p>\n<div style=\"aspect-ratio: 2878 \/ 822;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/swift-xcode.jpg\" title=\"Google Tag Manager iOS with Swift\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"822\" width=\"2878\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/swift-xcode.jpg#ZgotmplZ\" alt=\"Google Tag Manager iOS with Swift\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If you didn\u2019t know, <a href=\"https:\/\/developer.apple.com\/swift\/\">Swift<\/a> is a relatively new programming language, developed by Apple for iOS and OS X programming. It\u2019s got some nice synergies with existing Objective-C implementations, which means you can either gradually migrate to Swift, or just start writing new apps with it instantly.<\/p>\n<p>In this article, we\u2019ll walk through a simple Swift implementation of Google Tag Manager and Google Analytics. I\u2019ll very briefly review the GTM SDK in the Comments chapter, but this is a how-to article, not a why-should-I writeup. I\u2019m going to be expanding on this theme of mobile GTM in future texts, so this will stand out as a starting point for understanding how the SDK plays together with your application.<\/p>\n<p>Many thanks to my colleague, Sampsa Kuronen, for exposing me to the dark arts of Xcode and Swift.<\/p>\n<p>                <span class=\"simmer\"><br \/>\n  <span class=\"close\">X<\/span><\/p>\n<p>\n    <span class=\"fa fa-md fa-bell\"\/><br \/>\n    <strong>The Simmer Newsletter<\/strong>\n  <\/p>\n<p>\n    Subscribe to the <a href=\"https:\/\/www.simoahava.com\/newsletter\/\">Simmer newsletter<\/a> to get the latest news and content from Simo Ahava into your email inbox!\n  <\/p>\n<p>  <\/span><\/p>\n<h2 id=\"getting-started\">Getting started<\/h2>\n<p>This guide is written with the assumption that you\u2019re using the latest version of <a href=\"https:\/\/developer.apple.com\/xcode\/\">Xcode<\/a> as your IDE of choice. It\u2019s not the best IDE (by far) out there, but it has been created with iOS and OS X programming in mind, meaning there are certain benefits from using it.<\/p>\n<p>Another, quite obvious, assumption is that you have access to your project source. You will be <strong>adding new files<\/strong>, <strong>importing headers<\/strong> and <strong>modifying project source code<\/strong>. It\u2019s a good idea to run everything you\u2019re doing by your team, as you don\u2019t want to merge unverified source code into your project.<\/p>\n<p>Here\u2019s something you might not yet fully realize:<\/p>\n<p><strong>GTM for mobile apps <em>is not the same<\/em> as GTM for the web!<\/strong><\/p>\n<p>The level of freedom you have when working with the latter simply does not exist in the mobile app world. We\u2019re working with <strong>projects<\/strong> and <strong>applications<\/strong>, so you need to have a solid understanding of how to do software development in a proper and consistent manner, abiding to any design patterns you have found successful.<\/p>\n<h2 id=\"1-google-tag-manager-setup\">1. Google Tag Manager setup<\/h2>\n<p>To get things rolling, let\u2019s setup Google Tag Manager first. In this tutorial, we\u2019ll create a simple Screen View Tag to test the implementation with. In later chapters, we\u2019ll go over the event payload as well, but it\u2019s up to you to create the Tag for it.<\/p>\n<p>In GTM, create a new Container under some Account. Choose <strong>iOS<\/strong> as the container type, and give it a descriptive name.<\/p>\n<div style=\"aspect-ratio: 1218 \/ 750;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/create-container.jpg\" title=\"Google Tag Manager container\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"750\" width=\"1218\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/create-container.jpg#ZgotmplZ\" alt=\"Google Tag Manager container\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Next, you\u2019ll be whisked to the Container Overview, and you\u2019ll see a small popup saying your container is ready to use. You can close that.<\/p>\n<p>As you can see, it looks pretty much like GTM for web.<\/p>\n<p>Next, go to <strong>Tags<\/strong>, and click <strong>New<\/strong>.<\/p>\n<div style=\"aspect-ratio: 1978 \/ 462;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/tags-new.jpg\" title=\"New Tag\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"462\" width=\"1978\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/tags-new.jpg#ZgotmplZ\" alt=\"New Tag\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Wow, that\u2019s <strong>way fewer<\/strong> Tags than in GTM for web. Let\u2019s hope we\u2019ll get more soon! Also, make note that there is no <strong>Custom HTML Tag<\/strong>. It makes perfect sense, since you\u2019re not working with HTML, but I thought I should point it out nevertheless.<\/p>\n<p>We\u2019ll be creating a simple <strong>Google Analytics<\/strong> Tag , which sends an <strong>App View<\/strong> (also known as a Screen View) to Google Analytics when the first <strong>View<\/strong> of the app loads (don\u2019t worry, it will all be clear soon). So, create the Google Analytics Tag, and add the <strong>Tracking ID<\/strong>.<\/p>\n<p>Make sure that <strong>App View<\/strong> is selected as the Track Type, and expand <strong>More Settings<\/strong> -&gt; <strong>Fields to Set<\/strong>.<\/p>\n<p>Click <code>+ Add Field<\/code>, and add <strong>screenName<\/strong> as the Field Name. In Value, click the \u201cVariable\u201d button and choose <strong>New Variable\u2026<\/strong>.<\/p>\n<div style=\"aspect-ratio: 1732 \/ 882;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-variable.jpg\" title=\"new-variable\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"882\" width=\"1732\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-variable.jpg#ZgotmplZ\" alt=\"new-variable\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>We need to create a Variable, which picks up the desired Screen Name from the Data Layer (<em>Screen Name<\/em> is to an app what <em>Page<\/em> is to a website). So, after marvelling the list of Variables that\u2019s <a href=\"https:\/\/support.google.com\/tagmanager\/answer\/6106899?hl=en#mobile\">completely different<\/a> from GTM for web, choose <strong>Data Layer Variable<\/strong>.<\/p>\n<p>Give it a descriptive name, e.g. <strong>DLV &#8211; screenName<\/strong>, and set the Variable Name field to <strong>screenName<\/strong>. Save the new Variable.<\/p>\n<div style=\"aspect-ratio: 612 \/ 502;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/data-layer-variable-screenName.jpg\" title=\"data layer variable screenName\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"502\" width=\"612\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/data-layer-variable-screenName.jpg#ZgotmplZ\" alt=\"data layer variable screenName\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Next, in the Tag screen, click <strong>Continue<\/strong> and proceed to the <strong>Fire On<\/strong> step.<\/p>\n<p>In this step, click <strong>Custom<\/strong>, as you want to create a new Trigger for the Tag. So, in the popup that appears, click <strong>New<\/strong>.<\/p>\n<div style=\"aspect-ratio: 1154 \/ 578;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-trigger.jpg\" title=\"Create new Custom Trigger\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"578\" width=\"1154\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-trigger.jpg#ZgotmplZ\" alt=\"Create new Custom Trigger\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Give the Trigger a descriptive name, e.g. <strong>Event &#8211; screenView<\/strong>, and set the condition as in the screenshot below.<\/p>\n<div style=\"aspect-ratio: 1928 \/ 750;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/custom-trigger.jpg\" title=\"Custom Event Trigger\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"750\" width=\"1928\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/custom-trigger.jpg#ZgotmplZ\" alt=\"Custom Event Trigger\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Save the Trigger, and then click \u201cCreate Tag\u201d to, well, create the Tag.<\/p>\n<p>Phew, almost done here! We\u2019ll go with just this one Tag, as this is a simple setup guide.<\/p>\n<p>Next, go to the <strong>Versions<\/strong> page of your GTM container, and click open the <strong>Actions<\/strong> menu for the only container version you\u2019ll see (the initial draft). Click <strong>Publish<\/strong> and follow the prompts to publish your container.<\/p>\n<div style=\"aspect-ratio: 1962 \/ 920;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/publish-container.jpg\" title=\"Publish container\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"920\" width=\"1962\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/publish-container.jpg#ZgotmplZ\" alt=\"Publish container\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>There, GTM is <strong>almost<\/strong> ready, hungry to process the Data Layer commands you dispatch from your app.<\/p>\n<p>Just one more thing to do. You\u2019ll need to download the container version <strong>binary<\/strong>, as GTM for apps is a bit different in how it processes containers. Basically, you can\u2019t trust that the app will have access to a container downloaded over the network, so you\u2019ll always want to provide a local container binary file for the app as well. Read more about this in chapter 5.1.<\/p>\n<p>So, click open the <strong>Actions<\/strong> menu for the <strong>Live<\/strong> container version, and choose Download. Make sure you download it somewhere you can easily find it from.<\/p>\n<div style=\"aspect-ratio: 1720 \/ 764;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/gtm-download-container.jpg\" title=\"Download GTM container version\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"764\" width=\"1720\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/gtm-download-container.jpg#ZgotmplZ\" alt=\"Download GTM container version\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>That\u2019s it! We\u2019re done with the GTM setup. All that\u2019s left is the minor task of upgrading your App to use the Google Tag Manager (and Google Analytics) SDK!<\/p>\n<p>Congratulate yourself with a power bar and some coffee.<\/p>\n<p>I\u2019ll wait. Maybe get some coffee myself, and boogie silently to your profound success in setting up GTM!<\/p>\n<h2 id=\"2-create-a-new-xcode-workspace\">(2. Create a new Xcode workspace)<\/h2>\n<p>I won\u2019t linger here, as I\u2019m actually assuming you already have an <a href=\"https:\/\/developer.apple.com\/xcode\/\">Xcode<\/a> project and workspace to work with. If you need something to get started with, take a look at <a href=\"http:\/\/www.raywenderlich.com\/115279\/swift-2-tutorial-part-2-a-simple-ios-app\">this tutorial<\/a> by Ray Wenderlich. If you pay close attention to the screenshots in the article you\u2019re reading right now, you might notice that I\u2019m actually using Ray\u2019s Tip Calculator as the basis for this article.<\/p>\n<p>If you only have a project setup and no workspace, keep reading. When you add the required dependencies to your project using Cocoapods (see below), a workspace is automatically generated for you.<\/p>\n<h2 id=\"3-download-the-sdks-using-cocoapods\">3. Download the SDKs using Cocoapods<\/h2>\n<p>In order for Google Tag Manager to work with your app, you will need to download the SDKs for both Google Tag Manager and Google Analytics. To do that we\u2019ll use <a href=\"https:\/\/cocoapods.org\/\">Cocoapods<\/a>, which is an open-source dependency manager for your iOS and OS X projects. As you might have guessed, both Google Analytics and Google Tag Manager SDKs are also distributed as Pods.<\/p>\n<div style=\"aspect-ratio: 1907 \/ 641;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/cocoapods.jpg\" title=\"Cocoapods\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"641\" width=\"1907\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/cocoapods.jpg#ZgotmplZ\" alt=\"Cocoapods\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>After you\u2019ve installed Cocoapods (if you need help, check e.g. <a href=\"https:\/\/developers.google.com\/ios\/cocoapods\">this guide<\/a>), you need to go to your workspace root directory (the one with your .xcodeproj and .xcworkspace files), and type:<\/p>\n<p><code>pod init<\/code><\/p>\n<p>This command initializes a simple Podfile for your project.<\/p>\n<p>Open Podfile with your favorite editor.<\/p>\n<p>Between the lines <code>target 'YourProject' do<\/code> and <code>end<\/code>, you need to add the Pod references you want to download and install for your project, so add the following construct into the file:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\">target <span style=\"color:#a50\">'YourProject'<\/span> <span style=\"color:#00a\">do<\/span>\n  pod <span style=\"color:#a50\">'GoogleTagManager'<\/span>\n  pod <span style=\"color:#a50\">'Google\/Analytics'<\/span>\nend<\/code><\/pre>\n<\/div>\n<p>Once you\u2019ve done this, you can run the command <code>pod install<\/code>, which will automatically install and import all the files to your Xcode project. Neat, huh?<\/p>\n<div style=\"aspect-ratio: 1042 \/ 680;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/pod-install.jpg\" title=\"Install Google Analytics and google Tag Manager dependencies\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"680\" width=\"1042\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/pod-install.jpg#ZgotmplZ\" alt=\"Install Google Analytics and google Tag Manager dependencies\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Now that you\u2019ve installed the Pods, the next thing you need to do is import them into your project.<\/p>\n<p>It\u2019s not exactly straightforward, as Google Tag Manager source code is in Objective-C, which means you can\u2019t just directly import it to your Swift project. Instead, you need to use something called a <strong>Bridging Header<\/strong>.<\/p>\n<h2 id=\"4-create-and-edit-the-bridging-header-file\">4. Create and edit the Bridging Header file<\/h2>\n<p>A <em>bridging header<\/em> is key to creating projects where the codebase includes code from multiple languages &#8211; Objective-C and Swift in this case. Basically, you use a bridging header file to expose Objective-C structures in your Swift files, so that you can, for example, work with the GTM SDK (which is Objective-C at the time of writing) without having to worry about clashes and conflicts that occur when working across languages.<\/p>\n<p>First of all, if you installed the Pods correctly, you should see them in your <strong>Project navigator<\/strong>.<\/p>\n<div style=\"aspect-ratio: 516 \/ 360;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/tree-view.jpg\" title=\"Project navigator\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"360\" width=\"516\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/tree-view.jpg#ZgotmplZ\" alt=\"Project navigator\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Now, to create the bridging header file, go to <strong>File<\/strong> -&gt; <strong>New<\/strong> -&gt; <strong>File<\/strong>. Under <strong>iOS<\/strong> \/ <strong>Source<\/strong>, you\u2019ll find <strong>Header File<\/strong>, so select that and click <strong>Next<\/strong>.<\/p>\n<div style=\"aspect-ratio: 1458 \/ 1034;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/bridging-header-create.jpg\" title=\"Create new header file\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1034\" width=\"1458\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/bridging-header-create.jpg#ZgotmplZ\" alt=\"Create new header file\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Give the file a name: <code>yourProjectName-Bridging-Header.h<\/code>, and save it in your project root. Remember to choose a target for the file, so that the header file is properly associated with your project.<\/p>\n<div style=\"aspect-ratio: 858 \/ 656;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-header.jpg\" title=\"New header file settings\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"656\" width=\"858\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/new-header.jpg#ZgotmplZ\" alt=\"New header file settings\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You should see the file open in your editor. Add the following import statements to the file, and then save it:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">#<span style=\"color:#00a\">import<\/span> <span style=\"color:#a50\">\"TAGManager.h\"<\/span>\n#<span style=\"color:#00a\">import<\/span> <span style=\"color:#a50\">\"TAGContainer.h\"<\/span>\n#<span style=\"color:#00a\">import<\/span> <span style=\"color:#a50\">\"TAGContainerOpener.h\"<\/span>\n#<span style=\"color:#00a\">import<\/span> <span style=\"color:#a50\">\"TAGDataLayer.h\"<\/span>\n#<span style=\"color:#00a\">import<\/span> <span style=\"color:#a50\">\"TAGLogger.h\"<\/span>\n#<span style=\"color:#00a\">import<\/span> Google\/<span style=\"color:#0a0;text-decoration:underline\">Analytics<\/span>.<span style=\"color:#0a0;text-decoration:underline\">h<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>These headers include all the necessary Google Tag Manager headers, as well as all the Google Analytics SDK headers.<\/p>\n<p>Finally, you need to include the bridging header file in your build settings.<\/p>\n<p>Click your project (the root level node) in your Project navigator. In the settings screen that opens, choose the tag labelled <strong>Build Settings<\/strong>, and scroll all the way down to <strong>Swift Compiler &#8211; Code Generation<\/strong>.<\/p>\n<p>Edit the field next to <strong>Objective-C Bridging Header<\/strong>, and type in the file name of the bridging header file you just created.<\/p>\n<div style=\"aspect-ratio: 2878 \/ 1022;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/build-settings.jpg\" title=\"build-settings\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1022\" width=\"2878\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/build-settings.jpg#ZgotmplZ\" alt=\"build-settings\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Now, build your project and make sure everything checks out right.<\/p>\n<p>Next up, setting up Google Tag Manager in the project!<\/p>\n<h2 id=\"5-load-google-tag-manager-in-the-project\">5. Load Google Tag Manager in the project<\/h2>\n<p>My, how far we\u2019ve come!<\/p>\n<p>If you look at how the <a href=\"https:\/\/developers.google.com\/tag-manager\/ios\/v3\/\">developer guide kicks off<\/a>, you\u2019ll notice the rather limited capabilities of Google Tag Manager for mobile. For now, at least. Basically, you can dispatch Google Analytics hits and run custom functions. Also, you can change configuration values.<\/p>\n<p>In this tutorial, we\u2019ll focus on the first use case, so we\u2019ll setup a simple interface for tracking screen views and events to Google Analytics.<\/p>\n<h3 id=\"51-add-container-binary-to-project\">5.1. Add container binary to project<\/h3>\n<p>Before we do anything, however, we\u2019ll need to add the <strong>container version binary<\/strong> to the project. This is rather important, as even though GTM can load a \u201cfresh\u201d container over the network, some of the interactions on the site might actually need to be tracked <em>before<\/em> the asynchronous operation of loading the container is complete. In this case, GTM can fall back to the local container binary, also referred to as the <em>default<\/em> container.<\/p>\n<p><strong>NOTE!<\/strong> This also means that you should try to keep the binary in the project as up-to-date as possible, so that batches which use the binary would be as similar as possible to those that use the fresh container. So make it a habit that every time you publish a new container version, you download the version binary, and add it to the project (delete the old binary first).<\/p>\n<p>We\u2019ll cover all this very soon, don\u2019t worry.<\/p>\n<p>In Xcode, simply drag-and-drop the container binary file to your project. A window should open, where you need to make sure that you add the file to your target (so check the relevant box).<\/p>\n<div style=\"aspect-ratio: 1458 \/ 862;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/add-file.jpg\" title=\"Add container binary to project\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"862\" width=\"1458\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/add-file.jpg#ZgotmplZ\" alt=\"Add container binary to project\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If you don\u2019t have a <strong>Supporting Files<\/strong> group under your project, now\u2019s a good time to create one. Right-click on the container binary, and choose <strong>New Group from Selection<\/strong>. Name the group Supporting Files. Your navigator should look like this:<\/p>\n<div style=\"aspect-ratio: 514 \/ 194;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/supporting-files.jpg\" title=\"Supporting files group\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"194\" width=\"514\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/supporting-files.jpg#ZgotmplZ\" alt=\"Supporting files group\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If you already do have a Supporting Files group, just move the binary into that folder.<\/p>\n<p>Next up, <em>source code and stuff<\/em>.<\/p>\n<h3 id=\"52-modify-appdelegate\">5.2. Modify AppDelegate<\/h3>\n<p>The <strong>AppDelegate.swift<\/strong> file is where you control states of your app. For example, when the app loads, AppDelegate, well, <em>delegates<\/em> operations to different parts of your application. Similarly, when your phone rings and interrupts the application, you\u2019d control this process through AppDelegate.<\/p>\n<p>Since Google Tag Manager is something you want to load as the application loads, you\u2019ll need to make changes to AppDelegate.swift. So, proceed to open the file in your editor.<\/p>\n<p>We want to modify the function which is called once the application is loaded. Aptly, there\u2019s one that looks like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">application<\/span>(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: <span style=\"color:#0aa\">AnyObject<\/span>]?) -&gt; <span style=\"color:#0aa\">Bool<\/span> {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Override point for customization after application launch.<\/span>\n    <span style=\"color:#aaa;font-style:italic\">\/\/ ...<\/span>\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">true<\/span>\n}<\/code><\/pre>\n<\/div>\n<p>That\u2019s the callback we\u2019ll open the container in. Here, \u201copen the container\u201d means we\u2019ll make it available for dispatching hits using the available interfaces. On top of that, having a container available is a prerequisite for interacting with the <code>TAGDataLayer<\/code> interface. This is a slight departure, again, for how things work with GTM for web, where you could create a <code>dataLayer<\/code> object before the container loading began.<\/p>\n<p>Add the following lines into the function:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">tagManager<\/span> = TAGManager.instance()\nTAGContainerOpener.openContainerWithId(\n    <span style=\"color:#a50\">\"GTM-XXXXXX\"<\/span>,\n    tagManager: tagManager,\n    openType: kTAGOpenTypePreferFresh,\n    timeout: <span style=\"color:#00a\">nil<\/span>,\n    notifier: <span style=\"color:#00a\">self<\/span>)\n<span style=\"color:#aaa;font-style:italic\">\/\/ if DEBUG<\/span>\ntagManager.logger.setLogLevel(kTAGLoggerLogLevelVerbose)<\/code><\/pre>\n<\/div>\n<p>Line-by-line, here\u2019s what happens. First, you initialize an immutable variable named <code>tagManager<\/code> as a singleton instance of the <code>TAGManager<\/code> class.<\/p>\n<p>Next, you use the <code>TAGContainerOpener<\/code> interface to signal that you want to fetch a container to work with. Remember to change the <strong>\u201cGTM-XXXXXX\u201d<\/strong> to whatever the container ID you\u2019re using is.<\/p>\n<p>This next bit is a bit more complicated.<\/p>\n<p>When you download the container binary into the Supporting Files of your project, it\u2019s called a <em>default container<\/em>. This is what GTM uses until a saved container is found, or if this saved container is not fresh (&gt; 12 hours old), a new, fresh one is loaded over the network. This is why it\u2019s imperative that the saved binary is usable. The first screen view of the app might well be ready to dispatch before a non-default container has loaded, which means you want the default container to be as accurate as possible.<\/p>\n<p>When choosing the <code>openType<\/code> value, I suggest you use either <code>kTAGOpenTypePreferNonDefault<\/code> or <code>kTAGOpenTypePreferFresh<\/code>.<\/p>\n<p><code>kTAGOpenTypePreferNonDefault<\/code> attempts to load a saved container (i.e. one that was previously loaded over the network), regardless of whether it\u2019s stale or not. Stale means it\u2019s over 12 hours old. This means that you\u2019ll have a container to work with sooner. If the container is stale, Google Tag Manager starts an asynchronous request for a fresh container over the network.<\/p>\n<p><code>kTAGOpenTypePreferFresh<\/code> only loads a saved container if it\u2019s fresh. If it isn\u2019t, it loads a new, fresh container over the network.<\/p>\n<p>Both revert to the default container if a saved container couldn\u2019t be loaded or if there was a network error.<\/p>\n<p>Next, you can enable logging. I\u2019ve commented <strong>if DEBUG<\/strong> because it might be a good idea to verbosely log only if you\u2019re debugging the app, since it produces a <em>lot<\/em> of console output, which is unnecessary overhead in the live app.<\/p>\n<p>You might have noticed that I skipped over the <code>notifier: self<\/code> key-value pair in the <code>TAGContainerOpener<\/code> call. That\u2019s because it requires a bit more attention.<\/p>\n<p>The <code>notifier<\/code> parameter is basically a setting, where I instruct GTM to notify my app when a container becomes available. Once a container is available, our methods and functions can create an instance of the <code>AppDelegate<\/code> class to access the loaded container. You can use <code>container<\/code> to <a href=\"https:\/\/developers.google.com\/tag-manager\/ios\/v3\/#get-values\">update your app\u2019s configuration values<\/a> through GTM, for example.<\/p>\n<p>Because you\u2019re invoking <code>self<\/code> as the parameter value, it means that the class you\u2019re currently in (<code>AppDelegate<\/code>) needs to implement the <code>TAGContainerNotifier<\/code> protocol, as <code>self<\/code> is bound to an instance of the current class.<\/p>\n<p>Scroll up to the beginning of AppDelegate, and change the class declaration to:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">class<\/span> <span style=\"color:#0a0;text-decoration:underline\">AppDelegate<\/span>: UIResponder, UIApplicationDelegate, TAGContainerOpenerNotifier {\n    ...\n    <span style=\"color:#00a\">var<\/span> <span style=\"color:#a00\">container<\/span>: TAGContainer?<\/code><\/pre>\n<\/div>\n<p>In other words, you add the <code>TAGContainerOpenerNotifier<\/code> to the declaration line, and in the beginning of the class (so <em>not<\/em> in a <code>func<\/code>), you create a new variable <code>container<\/code>, which refers to a <code>TAGContainer<\/code> optional.<\/p>\n<p>Phew! Almost there.<\/p>\n<p>In the end of the class, after all the other <code>func<\/code> declarations, add a new one:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">containerAvailable<\/span>(container: TAGContainer) -&gt; <span style=\"color:#0aa\">Void<\/span> {\n    dispatch_async(dispatch_get_main_queue(), {\n        <span style=\"color:#00a\">self<\/span>.container = container;\n    });\n}<\/code><\/pre>\n<\/div>\n<p>And now things should start aligning in your mind.<\/p>\n<p><code>containerAvailable<\/code> is the callback that <code>TAGContainerOpener<\/code> invokes once a container becomes available. The container is passed as a parameter to this function.<\/p>\n<p>Next, we initialize <code>self.container<\/code> with the retrieved container. This way your app can use the loaded container through an instance of the <code>AppDelegate<\/code> class.<\/p>\n<p>By the way, here\u2019s a nifty trick. If you want to <strong>always<\/strong> load a fresh container over the network, you can add the following line to the <code>dispatch_async<\/code> callback:<\/p>\n<p>This forces a fresh container load over the network.<\/p>\n<p>How you want to load the container is completely up to you. Some methods, such as <code>container.refresh()<\/code>, impose more network requests than others, so it\u2019s always a compromise between freshness vs. availability vs. network load.<\/p>\n<p>Much of the container load process is explained <a href=\"https:\/\/developers.google.com\/tag-manager\/ios\/v3\/#open-advanced\">here<\/a>, though I have to say it\u2019s not very clearly documented at all (and it\u2019s in Objective-C).<\/p>\n<p>Now, build the project and make sure no errors pop up. You can run the project, and you should already see some verbose logging:<\/p>\n<div style=\"aspect-ratio: 2312 \/ 320;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/debug-verbose.jpg\" title=\"Verbose logging\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"320\" width=\"2312\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/debug-verbose.jpg#ZgotmplZ\" alt=\"Verbose logging\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You\u2019re ready to push stuff to the Data Layer to fire your Tags. Awesome!<\/p>\n<h2 id=\"6-push-stuff-to-data-layer\">6. Push stuff to Data Layer<\/h2>\n<p>This is where Google Tag Manager for apps is very similar to GTM for web. By invoking the <code>push<\/code> method of the Data Layer instance, GTM will react to the dictionary you push and fire any relevant Tags.<\/p>\n<p>To try it out, open a view controller file in your project. If it\u2019s a default project setup, there should be one named <code>ViewController.swift<\/code>.<\/p>\n<p>Now, to send the screen view, it makes sense to only send it once the view has loaded. So, find the method with the following signature, or create one if it doesn\u2019t exist:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">override<\/span> <span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">viewWillAppear<\/span>(animated: <span style=\"color:#0aa\">Bool<\/span>) {\n  <span style=\"color:#00a\">super<\/span>.viewWillAppear(animated)\n}<\/code><\/pre>\n<\/div>\n<p>Let\u2019s create an instance of <code>dataLayer<\/code> and push the payload to it. So modify the function to look like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">override<\/span> <span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">viewWillAppear<\/span>(animated: <span style=\"color:#0aa\">Bool<\/span>) {\n  <span style=\"color:#00a\">super<\/span>.viewWillAppear(animated)\n  <span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">dataLayer<\/span> = TAGManager.instance().dataLayer\n  dataLayer.push([<span style=\"color:#a50\">\"event\"<\/span> : <span style=\"color:#a50\">\"screenView\"<\/span>, <span style=\"color:#a50\">\"screenName\"<\/span> : <span style=\"color:#a50\">\"Home\"<\/span>])\n}<\/code><\/pre>\n<\/div>\n<p>First you create an immutable variable <code>dataLayer<\/code>, which is a reference pointing to the <code>dataLayer<\/code> interface of a <code>TAGManager<\/code> instance.<\/p>\n<p>Next, you do the <code>dataLayer.push()<\/code>, sending a dictionary with key-value pairs. As with GTM for web, the <code>'event'<\/code> is what makes things tick, and the other variables can (and will) be utilized if that\u2019s how you\u2019ve set the Tags up.<\/p>\n<p>Since we already have a Tag which uses the <code>'screenName'<\/code> variable, this code should work, sending a screen view with <strong>Home<\/strong> as the screen name.<\/p>\n<p>Go ahead, build the project and run your app. You should see something like this in the debugger:<\/p>\n<div style=\"aspect-ratio: 2352 \/ 784;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/10\/debugger-sent-hit.jpg\" title=\"Debugging sent hits\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"784\" width=\"2352\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/10\/debugger-sent-hit.jpg#ZgotmplZ\" alt=\"Debugging sent hits\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>As you can see, the <strong>&amp;cd;<\/strong> (for screen name) and <strong>&amp;t;<\/strong> parameters are right there, meaning the payload is OK. Then, there\u2019s the GET request to the Google Analytics endpoint, signalling that the payload has been dispatched.<\/p>\n<p>And that\u2019s it! You\u2019ve got a functioning Google Tag Manager installation in your hands.<\/p>\n<h2 id=\"bonus-simple-interface-for-interacting-with-the-data-layer\">BONUS: Simple interface for interacting with the Data Layer<\/h2>\n<p>Since we want to be slightly more ambitious, we can actually create an interface (or module) for interacting with the Data Layer. This way you can create elegant code in your app, simplifying some of the complex interactions and mitigating the risk of human error (e.g. typos).<\/p>\n<p>Create a new file called <strong>Analytics.swift<\/strong>. Add the following code within:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#00a\">import<\/span> <span style=\"color:#0a0;text-decoration:underline\">Foundation<\/span>\n\n<span style=\"color:#00a\">class<\/span> <span style=\"color:#0a0;text-decoration:underline\">Analytics<\/span> {\n    \n    <span style=\"color:#00a\">private<\/span> <span style=\"color:#00a\">static<\/span> <span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">dataLayer<\/span> = TAGManager.instance().dataLayer\n    \n    <span style=\"color:#00a\">private<\/span> <span style=\"color:#00a\">struct<\/span> <span style=\"color:#0a0;text-decoration:underline\">DataLayerMessage<\/span> {\n        <span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">event<\/span>: <span style=\"color:#0aa\">String<\/span>\n        <span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">ScreenName<\/span>: <span style=\"color:#0aa\">String<\/span>\n\n        <span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">getPayload<\/span>() -&gt; [<span style=\"color:#0aa\">String<\/span>:<span style=\"color:#0aa\">AnyObject<\/span>] {\n            <span style=\"color:#00a\">return<\/span> [<span style=\"color:#a50\">\"event\"<\/span> : <span style=\"color:#00a\">self<\/span>.event, <span style=\"color:#a50\">\"screenName\"<\/span> : <span style=\"color:#00a\">self<\/span>.screenName]\n        }\n    }\n \n    <span style=\"color:#00a\">static<\/span> <span style=\"color:#00a\">func<\/span> <span style=\"color:#0a0\">pushScreen<\/span>(screenName: <span style=\"color:#0aa\">String<\/span>) {\n        <span style=\"color:#00a\">let<\/span> <span style=\"color:#a00\">screenViewData<\/span> = DataLayerMessage(event: <span style=\"color:#a50\">\"screenView\"<\/span>, screenName: screenName)\n        dataLayer.push(screenViewData.getPayload())\n    }\n\n}<\/code><\/pre>\n<\/div>\n<p>Here, you create a new class called <code>Analytics<\/code>. Within, you define some variables, structs and methods that can be used by other parts of your app.<\/p>\n<p>You can expand the <code>DataLayerMessage<\/code> struct and the <code>pushScreen<\/code> method to include more extensive payloads, such as event objects (with category, action, label, and value), custom definitions, content groups and so forth.<\/p>\n<p>To send a screen view with this interface, all you need is the following command:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Analytics.pushScreen(<span style=\"color:#a50\">\"Some screen name\"<\/span>)<\/code><\/pre>\n<\/div>\n<p>The class will take care of the rest.<\/p>\n<p>It might seem complex, but it actually reduces a lot of overhead, since everything is neatly encapsulated in this single Analytics module.<\/p>\n<p>In later articles we\u2019ll use a similar structure in all the GTM interactions, so that things will stay nice and functional.<\/p>\n<p>It\u2019s not perfect, I\u2019ll give you that. You might wonder what the actual benefit is to just using the Google Analytics SDK, and you\u2019re right to feel a bit confused.<\/p>\n<p>However, as with GTM for web, the main benefit is with the Data Layer. Using the Data Layer interface lets you collect arbitrary semantic information from the app, and push it into the message queue without having to consider platform-specific implications. Instead, you can trust that whatever app uses the Data Layer will be able to transform the data to the form required by whatever endpoint it communicates with.<\/p>\n<p>And that\u2019s exactly why we spent some time to create a custom interface for interacting with Google Tag Manager. We want to <strong>decouple<\/strong> semantic information from actual app logic, only sending generic strings and dictionaries through the interface.<\/p>\n<p>This way, when GTM for apps hopefully expands and becomes richer and larger, you\u2019ll have the general infrastructure in place already, and implementing expansions and additions will happen organically and in a controlled, fluid manner, which leaves your app none the worse for wear.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>This has been a rather extensive tutorial for something as \u201csimple\u201d as setting up Google Tag Manager in your mobile app. Well, I hope that bubble has burst. It\u2019s not simple. It\u2019s not meant to be. You\u2019re messing with a <em>software project<\/em> for goodness sake. You don\u2019t want to mess up your chances with App Store review, or the hundreds of thousands of eager users that cringe if even the smallest thing is amiss in your beautiful app.<\/p>\n<p>GTM for mobile is not perfect. Far from it. There\u2019s still a lot to be done, and I hope the developers come up with some solid selling points for the platform, before people dismiss it entirely in favor of the pretty robust Google Analytics SDKs.<\/p>\n<p>To me, one of the biggest issues is, funnily enough, the terminology used. GTM for mobile <em>is so far removed<\/em> from GTM for web that it\u2019s weird they even share the same name. There are no \u201ctags\u201d in mobile development. It\u2019s just variables, classes, structs, dictionaries, functions, objects, etc.<\/p>\n<p>It\u2019s not \u201ctag management\u201d, it\u2019s app management, and as such it carries with it far greater risks than anything you could unleash on your website.<\/p>\n<p>And the risks are the main reason I want to stay far away from the value collection methods and the whole idea of updating configuration values of the app through GTM. A mobile app, being a software project, should be governed by the code base, and not some outside dependency.<\/p>\n<p>I don\u2019t understand why you\u2019d want to delegate app operations to a web-based control panel, when all it takes is a single failed network request and a slightly outdated default container to screw up the experience for the user. And I\u2019m sure that app users are less forgiving than web visitors, especially if the app costs money.<\/p>\n<p>Things like <strong>automatic screen tracking<\/strong> or <strong>automatic exception handling<\/strong> are not things I particularly miss, as creating the Analytics.swift module pretty much gives you a one-liner to track all your screenviews with (and events, if you extend it a little). Thus, ultimately it\u2019s the same effort as setting a <code>self.screenName<\/code> property or something.<\/p>\n<p>Other than the above, setting GTM for apps up is a breeze once you understand the logic. I love how I can use the Data Layer to decouple semantic information stored in the app from the app logic itself. I also love how I don\u2019t have to write analytics-specific syntax, and I can just use a generic Data Layer syntax instead. Perfection!<\/p>\n<p>I\u2019m looking forward to writing more about GTM for mobile soon. There are many ways you can improve the analytics tracking, and the SDK still has many tricks up its sleeve that you can use to facilitate your app tracking even further.<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve been meaning to write about Google Tag Manager for mobile apps for such a long time. Finally, I have some great use cases to share, as well as some useful examples for implementing GTM for iOS. That\u2019s right, this is an iOS guide, and, to be more specific, geared towards a successful Swift implementation. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":138700,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[1531,3554,14495,7003,11592,1791],"dealstore":[],"offerexpiration":[],"class_list":["post-138699","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-google","tag-ios","tag-manager","tag-setup","tag-swift","tag-tag"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Setup Google Tag Manager iOS With Swift - Som2ny Network<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fivemor.com\/?p=138699\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Setup Google Tag Manager iOS With Swift - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"I\u2019ve been meaning to write about Google Tag Manager for mobile apps for such a long time. Finally, I have some great use cases to share, as well as some useful examples for implementing GTM for iOS. That\u2019s right, this is an iOS guide, and, to be more specific, geared towards a successful Swift implementation. [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=138699\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-17T03:15:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"731\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=138699#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Setup Google Tag Manager iOS With Swift\",\"datePublished\":\"2025-03-17T03:15:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699\"},\"wordCount\":3983,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg\",\"keywords\":[\"Google\",\"iOS\",\"Manager\",\"Setup\",\"Swift\",\"TAG\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=138699#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=138699\",\"url\":\"https:\/\/fivemor.com\/?p=138699\",\"name\":\"Setup Google Tag Manager iOS With Swift - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg\",\"datePublished\":\"2025-03-17T03:15:28+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=138699#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=138699\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=138699#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg\",\"width\":2560,\"height\":731},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=138699#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Setup Google Tag Manager iOS With Swift\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fivemor.com\/#website\",\"url\":\"https:\/\/fivemor.com\/\",\"name\":\"Som2ny Network\",\"description\":\"Daily Deals\",\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fivemor.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fivemor.com\/#organization\",\"name\":\"Som2ny Network\",\"url\":\"https:\/\/fivemor.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"width\":300,\"height\":86,\"caption\":\"Som2ny Network\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/fivemor.com\"],\"url\":\"https:\/\/fivemor.com\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Setup Google Tag Manager iOS With Swift - Som2ny Network","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fivemor.com\/?p=138699","og_locale":"en_US","og_type":"article","og_title":"Setup Google Tag Manager iOS With Swift - Som2ny Network","og_description":"I\u2019ve been meaning to write about Google Tag Manager for mobile apps for such a long time. Finally, I have some great use cases to share, as well as some useful examples for implementing GTM for iOS. That\u2019s right, this is an iOS guide, and, to be more specific, geared towards a successful Swift implementation. [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=138699","og_site_name":"Som2ny Network","article_published_time":"2025-03-17T03:15:28+00:00","og_image":[{"width":2560,"height":731,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"21 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=138699#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=138699"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Setup Google Tag Manager iOS With Swift","datePublished":"2025-03-17T03:15:28+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=138699"},"wordCount":3983,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=138699#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg","keywords":["Google","iOS","Manager","Setup","Swift","TAG"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=138699#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=138699","url":"https:\/\/fivemor.com\/?p=138699","name":"Setup Google Tag Manager iOS With Swift - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=138699#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=138699#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg","datePublished":"2025-03-17T03:15:28+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=138699#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=138699"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=138699#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/swift-xcode-scaled.jpg","width":2560,"height":731},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=138699#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Setup Google Tag Manager iOS With Swift"}]},{"@type":"WebSite","@id":"https:\/\/fivemor.com\/#website","url":"https:\/\/fivemor.com\/","name":"Som2ny Network","description":"Daily Deals","publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fivemor.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/fivemor.com\/#organization","name":"Som2ny Network","url":"https:\/\/fivemor.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","width":300,"height":86,"caption":"Som2ny Network"},"image":{"@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","caption":"admin"},"sameAs":["https:\/\/fivemor.com"],"url":"https:\/\/fivemor.com\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/138699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=138699"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/138699\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/138700"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=138699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=138699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=138699"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=138699"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=138699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}