# App In-line Content

{% hint style="success" %}
Supported from Antsomi SDK v0.0.29.
{% endhint %}

App In-line Content allows you to insert content directly into your app's screen without disturbing the user experience. It also allows you to dynamically update your app's content and run relevant and contextual campaigns.

You may use the In-line Content to change areas of your app or show banner ads based on live triggers and segmentation.

{% hint style="warning" %}
This capability is provided in the Antsomi Media JSON feature. If you are not familiar with this feature, head over to this [document](https://docs.antsomi.com/cdp-365-user-guide-en/marketing-hub/media-json).
{% endhint %}

## **What is Media JSON?**

Media JSON acts as a structured data format that stores content and configuration information associated with Customer Journeys within CDP365. These Customer Journeys represent pre-defined sequences of interactions or touchpoints designed to engage users based on their behavior and attributes. By associating Media JSON with specific Customer Journeys, you can dynamically deliver personalized content to users at the right time.

## **Implementation with Antsomi Flutter SDK**

The Antsomi Flutter SDK offers functionalities to retrieve Media JSON for your Flutter applications. Here's a breakdown of the process:

{% hint style="warning" %}
Before continuing, please ensure that you've [added the Flutter SDK to your app](https://docs.antsomi.com/developers-guide/hybrid-apps/flutter/pages/BhbyiuwKsKIpSumMtIfV#id-1.-installation)[.](/developers-guide/hybrid-apps/react-native.md)
{% endhint %}

### 1. Retrieving Media JSON data

Once you have access to the initialized `AntsomiSDK` instance (assuming you've completed the [initialization steps](/developers-guide/hybrid-apps/flutter.md) as documented by the Antsomi SDK provider), you can utilize the `getMediaJson()` method in the screen that you want to display the App In-Line Content by following:

{% tabs %}
{% tab title="Dart" %}

```dart
import 'package:antsomisdk/antsomi.dart'; // Contains Antsomi SDK APIs
import 'package:antsomisdk/cdp_event.dart'; // Contains Antsomi SDK APIs
import 'package:antsomisdk/media_json.dart'; // Contains the Catalog class

final event = CDPEvent(en: 'view_screenview');
event.eventProps = {'screen_name': 'templateMediaJson'};

const storyId = '123';

// Initialize AntsomiSDK object
antsomiSdk = Antsomi();
final MediaJson mediaJson = await antsomiSdk.getMediaJson(event: event, storyId: storyId);
```

{% endtab %}
{% endtabs %}

This method takes two arguments:

<table><thead><tr><th width="226">Field</th><th width="211">Data Type</th><th>Description</th><th data-hidden>Description</th></tr></thead><tbody><tr><td><code>event</code></td><td><code>CDPEvent</code></td><td>The specific event name corresponds to the event configured within your CDP365 workspace to initiate the relevant Customer Journey.</td><td>A unique identifier specifying the message destination.</td></tr><tr><td><code>storyId</code></td><td><code>String</code></td><td>(Optional) Allows you to specify a particular journey within the Customer Journey triggered by the <code>event</code>. If omitted, the Media JSON for the default journey associated with the event will be retrieved.</td><td>A classification parameter for targeted messaging. <br>Each destination can target to one type of audience only.</td></tr></tbody></table>

The retrieved `MediaJson` is a structured data format containing various properties relevant to personalization. While the exact structure might vary depending on your CDP365 configuration, here's a general overview of the common elements:

<table><thead><tr><th width="257">Field</th><th width="206">Data Type</th><th>Description</th><th data-hidden>Description</th></tr></thead><tbody><tr><td>status</td><td>bool</td><td>The status of getting the Media JSON, always check this key first to prevent errors.</td><td></td></tr><tr><td>webContents</td><td>Map&#x3C;string, dynamic>?</td><td>This key contains the main content data.</td><td></td></tr><tr><td>  contents</td><td>Map&#x3C;string, dynamic></td><td>This nested map holds the actual content associated with the Customer Journey.</td><td></td></tr><tr><td>    globalTracking</td><td>Map&#x3C;string, dynamic></td><td>This map might contain global tracking information like <code>impression</code> and <code>view</code> URLs or UTM modules used for tracking purposes within CDP365.</td><td></td></tr><tr><td>      view</td><td>String</td><td>The global <code>view</code> URL tracking information.</td><td></td></tr><tr><td>      impression</td><td>String</td><td>The global <code>impression</code> URL tracking information.</td><td></td></tr><tr><td>      atmTrackingParameters</td><td>String</td><td>The global UTM/ATM modules string. </td><td></td></tr></tbody></table>

### 2. Utilizing Retrieved Media JSON

Once you have successfully retrieved the Media JSON object, you can leverage the data to personalize user experiences within your Flutter applications. Here are some potential use cases:

#### **Populate UI Elements**

For example, take a look at a Media JSON configured as below:

<figure><img src="/files/eM8PHKOhnKTSASl5Tc65" alt=""><figcaption><p>[App Retail PRODUCT RECOMMEND] - Media JSON</p></figcaption></figure>

With this setup, we can extract dynamic content from the `dynamicContent` object and use it to populate UI elements like images, product names, prices, or descriptions to recommend our end-users with the latest trending products as the following:

{% tabs %}
{% tab title="Dart" %}

```dart
@override
Widget build(BuildContext context) {
    return Scaffold(
    // ... More code here
    child: Container(
        height: 200, // Adjust the height as needed
        color: Colors.white,
        child: SingleChildScrollView(
            controller: _scrollController,
            scrollDirection: Axis.horizontal,
            child: Row(
                children: dynamicContent.map((content) {
                  return GestureDetector(
                    onTap: () {
                      // onTap() handlers...                      
                  },
                  child: SizedBox(
                    width: 150, // Adjust the width as needed
                    child: Column(
                      children: [
                        Image.network(
                          content['image_url'],
                          height: 150,
                        ), // Image.network
                        Text(content['name']),
                        Text(content['price']),
                      ],
                    ), // Column
                  ), // SizedBox
                ); // GestureDetector
              }).toList(),
            ), // Row

    // ... More code here
```

{% endtab %}
{% endtabs %}

And you will receive something similar to this

<figure><img src="/files/uL76Lue6b9o6ryrd4mA3" alt=""><figcaption><p>Sample Result - App In-Line Content show the list of Recommended Products</p></figcaption></figure>

### **3. Trigger Tracking Events**&#x20;

Utilize tracking URLs found within the `globalTracking` map (if applicable) to trigger events within CDP365 based on user interactions with personalized content such as impression, viewable, item clicked, or UTM tracking.

For instance, let's say we are building a section that shows a list of personalized recommended products for our end-users, these products are precisely selected via our algorithms and delivered to each end-user through the Customer Journeys.

#### Impression Event

When the screen is loaded and you have successfully requested the list of the recommended products. This is the **impression event** that should be fired as soon as the request is successfully made.  After invoking the `getMediaJson()` and getting the list of recommended products, please invoke this function:

{% tabs %}
{% tab title="Dart" %}

```dart
if (mediaJson.webContents?['contents']?['globalTracking']?['impression'] != null) {
    antsomiSdk.handleTrackingUrl(url: Uri.parse(mediaJson.webContents!['contents']!['globalTracking']!['impression']));
}
```

{% endtab %}
{% endtabs %}

#### Viewable Event

When a user scrolls down the screen the specific recommended products section is displayed. This is the **viewable event**. This event should be fired once the section is partially visible. After making the API request and getting the list of recommended products, and the displayed section is partially visible, invoke the function like the example below:

{% tabs %}
{% tab title="Dart" %}

```dart
// Check visibility when the screen is loaded
WidgetsBinding.instance.addPostFrameCallback((_) {
  if (_isRowVisible()) {
    // Check if the second row is visible when the screen is loaded
    if (mediaJson.webContents?['contents']?['globalTracking']?['view'] != null) {
      antsomiSdk.handleTrackingUrl(url: Uri.parse(mediaJson.webContents!['contents']!['globalTracking']!['view']));
    }
  }
});
```

{% endtab %}
{% endtabs %}

**Click Item Event**

When the list of recommended products is loaded, and our user taps on any one of them. This is the **click item event**. This event should be fired once the section is partially visible. After making the API request and getting the list of recommended products, and the displayed section is partially visible, invoke the function like the example below:

{% tabs %}
{% tab title="Dart" %}

```dart
@override
Widget build(BuildContext context) {
    return Scaffold(
    // ... More code here
    child: Container(
        height: 200, // Adjust the height as needed
        color: Colors.white,
        child: SingleChildScrollView(
            controller: _scrollController,
            scrollDirection: Axis.horizontal,
            child: Row(
                children: dynamicContent.map((content) {
                  return GestureDetector(
                    onTap: () {
                        if (content['page_url_with_tracking_click'] != null) {                            
                            var trackingLink = Uri.parse(content['page_url_with_tracking_click']);
                            AntsomiSDK.instance.handleTrackingUrl(url: trackingLink);
                            
                            // Redirect your end-user to the Product Screen here...
                        }
                  },
                  child: SizedBox(
                    // ... More code here
                ); // GestureDetector
              }).toList(),
            ), // Row

    // ... More code here
```

{% endtab %}
{% endtabs %}

**ATM/UTM Tracking**

And finally, what if you want to set some UTM/ATM tracking modules so that you can unify the source of events, just simply include the value of the `atmTrackingParameters` in the `globalTracking` map and invoke the `handleDeepLink()` method. From now on, every event that our SDK tracked will be automatically included with this UTM/ATM tracking module.

{% tabs %}
{% tab title="Dart" %}

```dart
@override
Widget build(BuildContext context) {
    return Scaffold(
    // ... More code here
    child: Container(
        height: 200, // Adjust the height as needed
        color: Colors.white,
        child: SingleChildScrollView(
            controller: _scrollController,
            scrollDirection: Axis.horizontal,
            child: Row(
                children: dynamicContent.map((content) {
                  return GestureDetector(
                    onTap: () {
                        if (content['page_url_with_tracking_click'] != null) {
                            var deepLink = Uri.parse(content['page_url'] + '?' + globalTracking?['atmTrackingParameters']);
                            var trackingLink = Uri.parse(content['page_url_with_tracking_click']);
                            
                            antsomiSdk.handleDeepLink(url: deepLink);
                            antsomiSdk.handleTrackingUrl(url: trackingLink);
                            
                            // Redirect your end-user to the Product Screen here...
                        }
                  },
                  child: SizedBox(
                    // ... More code here
                ); // GestureDetector
              }).toList(),
            ), // Row

    // ... More code here
```

{% endtab %}
{% endtabs %}

***

By effectively utilizing App In-line Content and the Antsomi Flutter SDK, you can create a more dynamic and engaging user experience within your Flutter applications. This capability allows you to deliver personalized content, trigger relevant campaigns, and gain valuable insights into user interactions. Remember to refer to the specific documentation provided by your chosen App In-line Content solution for detailed integration steps and functionalities.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.antsomi.com/developers-guide/hybrid-apps/flutter/app-in-line-content.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
