Published using Google Docs
Promoted.ai Integration Guide Summary Jan 2021
Updated automatically every 5 minutes


Integration Guide Summary

January 2021

PRODUCT INTEGRATION SUMMARY        2

Overall System Diagram        3

Integration Goals        4

Goal: Show promotions in your product        4

Goal: Log events so Promoted.ai can optimize and report delivery metrics.        5

Goal: Enable Self-Service Promotion Management for Promoters        6

Goal: Billing        6

Goal: Authentication        7

How long will the integration take?        7

How should we approach integration?        7

ENGINEERING DOCUMENTATION        8

APIs        8

Delivery: Show Promotions and/or Optimize Ranking        8

Delivery API Documentation        8

Delivery SDK        8

Overview        8

1. Call the Promoted.ai’s Delivery by sending a Request.        9

API ENDPOINT        10

Request        10

2. Await the corresponding Server API Response        11

Response        11

3. Incorporate the Response into your Controller layer and send the client device item rendering instructions        12

4. Change your client interfaces to change how promotion content is rendered.        12

Metrics: Log Events        13

Metrics API Documentation        13

Metrics SDK        13

Web        13

iOS        13

Android        13

Overview        13

1. Logging events (User, Sessions, Queries, Impressions, Clicks).        14

Request        14

Response        16

1.A - Logging User data        17

1.B - Logging Session data        17

1.C - Logging Queries        18

1.D - Logging Insertions        19

1.E - Logging Impressions        20

1.F - Logging Clicks        21

Manager API - Create and View Promotions and Statistics        22

Manager API Documentation        22

Manager SDK        22

Manager Overview        22

Manager How-To: Map Entity Model        22

1. Map your platform’s domain model to the Promoted.ai domain model.        22

Manager API - Very Simple UI        25

1. Create Content entities in Promoted.ai so that they can be promoted.        25

2. For promoters, embed a simple embedded UI into your product UI.        25

3. Provide a link to Promoted.ai’s branded white-label Manager UI        27

Manager API - Completely Native Solution        28

Authentication and Authorization        28

Billing        28

User Experience (UX)        29

Legal        30

Sales and Services Support        30

Administration Manager UI        30

Seller to Promoter Conversion Features        30

Consulting and Analytics        30

PRODUCT INTEGRATION SUMMARY

Promoted.ai offers a first-party, native promotion listings platform as a managed service.  You will integrate with Promoted.ai using our three main APIs:

The Delivery API and Metrics API are JSON-RPC HTTP APIs.  The Manager API is a GraphQL API. Learn more about GraphQL API at https://graphql.org.

SDKs are provided per service in various common languages.

Overall System Diagram

Solution Package System Diagram

Delivery, Metrics, and Manager work together to optimize user experience and revenue in a real-time loop of recommendations, measurement, learning, and response. In this integration diagram, only Paid Manager is used.

  1. The Client Device (web or mobile) sends a request to the customer’s product backend.
  2. The customer’s backend Controller retrieves a sample of items that can be shown.
  3. The list of items and request context are sent to Promoted Delivery.
  1. [if enabled] Organic Delivery predicts what allocation of items the user will like best.
  2. [if enabled] Paid Delivery re-ranks or inserts promoted items based on a paid auction.
  1. Promoted Delivery returns the recommended allocation of items with metadata, including quality scores and prices.
  2. The customer’s Controller may manipulate the results returned by Promoted before returning the result to the Client Device for rendering.
  3. The Client Device displays the items to the user. All insertions, impressions, and user engagements are sent to Metrics for immediate reactive modeling and promotion billing. Metrics are also streamed to Manager for real-time reporting for Promoters.

Integration Goals

Goal: Show promotions in your product

Figure 1: Workflow of showing promotions in your product.

Goal: Log events so Promoted.ai can optimize and report delivery metrics.

Figure 2: Workflow of logging real-time events in your product.

Goal: Enable Self-Service Promotion Management for Promoters

If promoting organic content, or content that may appear in the product without promotion:

For all configurations:

Goal: Billing

Goal: Authentication

How long will the integration take?

Depends on the size of the platform code base:

You will need time from Engineering, Product Management, UI Designers, Legal, Sales and Support.

A simple integration on a small platform can take 2-4 engineer weeks.  A complex integration on complex platforms can take several months. Additional optimizations and system tuning can take additional months.

Side-note: most of this integration work is required even if you decide to implement your own promoted listing platform. You would need to do this integration work to integrate with your own in-house solution, too.

How should we approach integration?

Tips:

ENGINEERING DOCUMENTATION

APIs

Promoted.ai APIs use JSON-encoded request bodies, JSON-encoded responses, and standard HTTP response codes and authentication.

The Manager API is a GraphQL API. Learn more about GraphQL API at https://graphql.org.

The Delivery and Metrics APIs use custom request/response objects.  This document describes our verbose format.  A mini-JSON format will also exist soon.  We are evaluating exposing a Protocol Buffer gRPC for these interfaces for improved network transfer and response latency efficiencies.

Delivery: Show Promotions and/or Optimize Ranking

Delivery API Documentation

Coming Soon.

Delivery SDK

Coming Soon.

Overview

System Diagram for Delivery. Delivery does not interact with any client device.

See Simple Serving API JSON Schema for more information on organic ranking with native promotions.

You call the Delivery API by constructing and sending a Request object to the API Endpoint, awaiting the Response from the API Endpoint, and then adjusting your product’s client display to display and render the promotions as instructed by the Response. In Promoted.ai’s backend, prices will be computed per the Auction, and various control systems will be updated, but promotion billing events do not happen until the appropriate billable event (e.g., impression, click, MRC video view) is sent to Promoted.ai Event server.

Figure 1(2): Workflow of showing promotions in your product.

1. Call the Promoted.ai’s Delivery by sending a Request.

Call the Promoted.ai Delivery API from the controller layer, sometimes called the application layer, of your application, i.e., the server that handles user requests and returns responses to the client. This is the fastest and most secure way to interact with Promoted.ai.

Promoted.ai can be called directly from the client without first interacting with your controller layer servers. This can sometimes be easier to integrate, especially for rapid prototyping. However, this option is much slower and is less secure.

API ENDPOINT

https://api.promoted.ai/v1/serve

Request

The Request describes all the Content items that would or could appear in the product if there were no promotions. If items will be rendered, then they need to have a position identifier, which is an ordinal index of allocation positions to be rendered in the client. In general, lower indices are displayed more prominently in the client device, i.e., at the top, the left, and/or first. These indices can be platform, product area, client device specific, and configuring them with Promoted.ai is a part of our onboarding process. If the Content item can be displayed if it is promoted, but it otherwise would not be displayed in any position, then do not set the position attribute for that item.

Each content item has a list of optional and platform-specific attributes that helps Promoted.ai determine the value of showing a particular item in a particular location. These attributes are platform specific, and are configured in your platform’s onboarding process. Examples of these attributes include quality scores, click and other event predictions, and media type.

Note: To keep the targeting consistent between organic and promotions, we rely on your platform passing potential promotion candidates in the Request. Promoted.ai currently does not yet support its own retrieval system for promotions. It relies on your product, via the Request, to determine what items can be shown per Response. Inserting items that do not appear in the Request is a future feature.

The Request can also include additional information about the product display context: user, session and query.  This additional information is used to help Promoted.ai better estimate the value of different promotions and in our machine learning models, and is, again, customized per platform in our onboarding process.

Full Request JSON Body

{
 platformId:
"1",
 userId:
"abc",

  query: "pizza",
 contents: [
   {
     id:
"xyz1",
     quality:
0.7,
     position:
1,
   },
   {
     id:
"xyz2",
     quality:
0.69,
   },
   ...
 ],
 session: {
   /* Client generated UUID */

    sessionId: "f9e88837-f9c8-4b70-b928-a9972d55c7c3",
   /* Set a geo field to use default privacy settings. */
   ipAddress:
"1.2.3.4",
 },
}

Figure 3: Request Object Example in Delivery API

2. Await the corresponding Server API Response

Response

{
 insertions: [
   {
     id:
"xyz1",
     position:
1,

      isPromoted: True,
     insertionId:
"d9f34617-455a-4b3e-a778-0bbe51cac0dd",
   },

    {
     id:
"xyz3",
     
position: 2,
     insertionId:
"7f7103c0-b59d-4cdf-b4d4-8b63601f860e",
   },
   ...
 ],
}

Figure 4: Response Object Example in Delivery API

After sending the Request to the Promoted.ai Server API, the Server will send back a Response object to that same process after a brief processing delay to run the promotion auction. The Response includes a list of Content items called insertions. The Content items in insertions are a subset of the items passed in the Request with specified allocation positions for display in the product and in the client, a flag for promoted status, and other optional display metadata that is platform-specific. Because non-promoted items can be moved to accommodate promotions, both promoted and unpromoted items appear in the insertions list.

Insertions become impressions, or user-viewed items, when the content item is displayed in the client device given a certain degree of completeness and length of time. Not all insertions are viewed by users, e.g., the user does not scroll to the bottom of the page. An impression is an event that is sent to the Promoted.ai Event server.

3. Incorporate the Response into your Controller layer and send the client device item rendering instructions

The Response object returned by Promoted.ai is how your product should render items, but the information in it needs to be interpreted and incorporated into your existing controller layer application code. Then, send the resulting product client response to the user client device for device rendering.

On your serving response, pass through new info:

4. Change your client interfaces to change how promotion content is rendered.

Update your apps, web UIs and external APIs to support the display of promoted items. How you choose to do this platform specific, but in the USA, FTC rules state that native advertising must be differentiable from non-promoted contents and clearly identified as advertised. A small “promoted” visual tag is common practice. See: https://www.ftc.gov/tips-advice/business-center/guidance/advertising-marketing-internet-rules-road

Example: add a text label, like “promoted”, to your items to make it clear they are promotions.

Metrics: Log Events

Metrics API Documentation

Coming Soon.

Metrics SDK

Metrics SDKs are based on Snowplow client integrations. See Snowplow Docs

Web

See open source directories:

iOS

See open source directory:

https://github.com/promotedai/ios-objc-sdk-metrics

Android

Coming Soon.

Overview

System Diagram for Metrics. Both the client and the partner server send events to Metrics.

Figure 5: Example flow to log impressions and clicks.

For Promoted.ai to respond to, aggregate, and report events in your system, those events need to be sent to Promoted.ai via the Metrics API.

1. Logging events (User, Sessions, Queries, Impressions, Clicks).

Logging can be done from your servers or client code. We recommend that events are logged to Promoted.ai in real-time so Promoted.ai can optimize and provide reports in real-time.

Request

The request body uses JSON.

The definitions below use Protocol Buffer.  Our interface accepts the JSON version of the Protocol Buffer interface.

Protocol Buffer definition

// A way to batch up log requests into the same request.
// Clients can reference logs in different batches.
message BatchLogRequest {
 
uint64 platform_id = 1; // Required
 
string user_id = 2; // Required
 
uint64 time_epoch_millis = 3; // Optional. Default timestamp for events.
 
repeated User user = 10;
 
repeated Session session = 11;
 
repeated Query query = 12;
 
repeated Insertion insertion = 13; // Promoted.ai logs these for promotions.
 
repeated Impression impression = 14;
 
repeated Click click = 15;
}

JSON example to log impressions:

{
 platformId:
"1",
 userId:
"abc",
 impression: [
   {
     /* Client generated UUID */
     impressionId:
"2bb0316d-3539-494a-bb4e-4490892bdc5c",
     insertionId:
"d9f34617-455a-4b3e-a778-0bbe51cac0dd",
   },
   ...
 ]
}

These repeated lists have size limits of < 1kB.  You can refer to IDs in different batches.

This batch log request contains multiple types of data.

Each of these log types has a primary ID.

If multiple logs are sent with the same identifiers, Promoted.ai tries to merge the latest changes onto previous logs using the primary ID (depends on the delay and which log type) and a time window.  This is useful if you want to update properties on User or Session.  Most log types will only check for duplicates in a small time window around the timestamps (~24 hours).  User data can be updated years into the future.

Response

On success, the body will have an empty json object “{}”.  On error, the body will contain an error message.

We expect most client calls to fire and forget (not wait for the response).  It’s recommended to infrequently wait for the response to verify that the connection is working correctly.

1.A - Logging User data

To optimize auction performance, log User and Session data early in the end-user’s experience.

The User logs store personal data and settings.  Most of the v1 data will go into the custom KeyValue section.

Protocol Buffer definition

// Used to store user properties.  E.g. purchasedContentIds.
// Clients can update each User multiple times by logging the User
// with the same user_id.  Unset fields will not be updated. Repeated // fields will act like a merge if the item has a key.  Otherwise,
// it'll act like an append.
message User {

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
uint64 platform_id = 1;

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
string user_id = 2;

 
// Internal.  Request timestamp.
 
uint64 time_epoch_millis = 3;

 
repeated KeyValue key_value = 10;
}

1.B - Logging Session data

Log Session data ASAP when the Session is started so Promoted.ai’s Serving stack can use the information.  There are options for passing this in directly on the Delivery API request.

Protocol Buffer definition

// A period of activity by a single User.  Users can have multiple
// Sessions. Clients can update a Session multiple times by logging
// multiple Sessions with the same session_id.  Unset fields will not
// be updated.  Repeated fields will act like a merge if the item has
// a key.  Otherwise, it'll act like an append.
message Session {
 
uint64 platform_id = 1; // Optional if set on BatchLogRequest.
 
string user_id = 2; // Optional if set on BatchLogRequest.
 
uint64 time_epoch_millis = 3; // Log timestamp.
 
string session_id = 11; // Required. Primary ID.

 
// Optional. Start time.
 
uint64 start_time_epoch_millis = 12;

 
// Optional. End time.
 
uint64 exclusive_end_time_epoch_millis = 13;

 Device device =
14;
 Browser browser =
15;

 
// Location.  At least one location value needs to be set so we can
 
// default privacy settings.
 
// Optional.  We'll use IP Address to guess the user's location.
 oneof ip_address {
     
fixed32 ip_address_v4 = 16;
     
bytes ip_address_v6 = 17;
 }
 
// Optional.  Clients can specify latitude and longitude directly.
 
double longitude = 18;
 
double latitude = 19;

 
// Optional.  Can be a full referrer string.  Could be just the UTM.
 
string referrer = 20;

 
// Used to store custom values.
 
repeated KeyValue custom_value = 30;
}

1.C - Logging Queries

For promotions, Promoted.ai logs Queries inside the Delivery API call. If you want organic (non-promotion) queries logged, log the query directly in a separate call to the Metrics API.

Protocol Buffer definition

// A collection of Insertions.
message Query {

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
uint64 platform_id = 1;

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
string user_id = 2;

 
// Internal.  Request timestamp.
 
uint64 time_epoch_millis = 3;

 
// Required.  This is a UUID that is generated by the client.
 
string query_id = 10;

 
// Required.
 
string session_id = 11;

 
// Optional.  This is the name of where the content is served.  It's recommended to set this.
 
// Q - how should this work with experiments?  Should we handle experiments separately?
 
string surface_name = 12;

 
// Internal. Dictionary ID. We'll use this to optimize storage.
 
// This will be stored at the platform level.
 
int32 surface_id = 13;

 
// Used to store custom values.
 
repeated KeyValue custom_value = 30;
}

1.D - Logging Insertions

For promotions, Promoted.ai logs Queries in the Delivery API call. Ordinarily, these are not sent as separate Metrics API calls from your servers to Promoted.ai.

Protocol Buffer definition

// This Event represents a Content being served at a certain position regardless
// of it was views by a user. Insertions are immutable.
message Insertion {

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
uint64 platform_id = 1;

 
// Required.  Can be optional if set on a wrapping BatchLogRequest.
 
string user_id = 2;

 
// Internal.  Request timestamp.
 
uint64 time_epoch_millis = 3;

 
// Required.  This is a UUID that is generated by the client.
 
string insertion_id = 10;

 
// Required.
 
string query_id = 11;

 
// Optional.  We'll look this up using the external_content_id.
 
uint64 content_id = 12;

 
// Required.
 
string external_content_id = 13;

 
// Optional.
 
uint64 position = 14;

 
// Internal.
 promotion.InsertionLogFlatPromotion insertion_log_flat_promotion =
15;

 
// Used to store custom values.
 
repeated KeyValue custom_value = 30;
}

1.E - Logging Impressions

Log these in real-time, when Content items are displayed in the client by users, so Promoted.ai can update our automated bidders with recent results.  Multiple impressions may be logged on the same BatchLogRequest.

Protocol Buffer definition

// When an Insertion is shown to a user.
// Impressions are immutable.
message Impression {
 
uint64 platform_id = 1; // Required.  Optional if set on BatchLogRequest.
 
string user_id = 2; // Required.  Optional if set on BatchLogRequest.
 
uint64 time_epoch_millis = 3; // Time of the click.

 
// Required. This is a unique ID for the Impression.
 
string impression_id = 10;

 
// Required.  This matches Insertion.insertion_id.
 
string insertion_id = 11;

 
// Optional. Used to store custom values. Most platforms will not need to set any custom_values on clicks.
 
repeated KeyValue custom_value = 30;
}

1.F - Logging Clicks

Log these in real-time, when Content items are clicked in the device client by users, so Promoted.ai can update our automated bidders with recent results.  Multiple clicks may be logged on the same BatchLogRequest.

Protocol Buffer definition

// Clicks are immutable.
message Click {
 
uint64 platform_id = 1; // Required.  Optional if set on BatchLogRequest.
 
string user_id = 2; // Required.  Optional if set on BatchLogRequest.
 
uint64 time_epoch_millis = 3; // Time of the click.

 
// Required. This is a unique ID for the click.
 
string click_id = 10;

 
// Required. This matches Impression.impression_id.
  string impression_id = 11;

 
// Optional. Used to store custom values. Most platforms will not need to set any custom_values on clicks.
 
repeated KeyValue custom_value = 30;
}

Manager API - Create and View Promotions and Statistics

Manager API Documentation

GraphQL Manager API Documentation

Manager SDK

Coming Soon.

Manager Overview

System Diagram for Manager. End-users and internal staff can use manager via the API or the Web UI.

Manager How-To: Map Entity Model

1. Map your platform’s domain model to the Promoted.ai domain model.

The Promoted.ai domain model has entities for advanced use cases that you might not want to expose in the V1 integration.

Here is a brief description of Promoted.ai’s core entities (using our terminology).  This might be confusing if your platform uses these terms for other entities.  The full Manager UI will allow renaming of the names of the UI text (e.g. “Content” -> “Product”, “Listing”, “Video”, etc).

Figure 6: Promoted.ai Abstraction mapping

Design Question - do you want to model the relationship using persisted relationships or dynamic relationships?

We recommend using a persisted relationship for mapping Accounts and a dynamic relationship for mapping Platform-side Content to Campaigns and Promotions.

Here are some common initial mappings:

The next section gives example queries for the mapping.

Platform settings can be used to limit configurations.

Manager API - Very Simple UI

This section designs a simple embedded UI: a checkbox to enable promotions, a daily budget textbox and a link to the full external Manager UI. This is our next easiest promoter manager solution after our white-label UI.

1. Create Content entities in Promoted.ai so that they can be promoted.

Here is an example GraphQL call for creating Content.  Run this once to bulk populate Content and then regularly whenever the server-side changes.  If you only want to store promoted Content in Promoted.ai, call this during the enabling process.  This call should be performed by a user or service account with Platform-level permissions (not using the promoter authentication).

mutation {
 createContent(input: {
   
platformId: "1",
   name:
"The content's name",
   externalId:
"The ID in your system"
 })
}

# Mutations can also be done in batches.
mutation {
 content1: createContent(input: {
   
platformId: "1",
   name:
"The content's name",
   externalId:
"The ID in your system"
 }),
...
}

2. For promoters, embed a simple embedded UI into your product UI.

Add a checkbox to content to enable promotions and add a link to the full Manager UI.

For the basic integration, use your Platform’s Content ID (we call them externalContentId) as the mapping to pull all of the promotion entities.  You can also use a filter for accountId depending on the desired calls.

Here is an example GraphQL query to get the statuses of the entities if you only have the externalContentId.

{
 promotionConnection(input:{
   where: {
     platformId: { is:
"1" },
     externalId: { is:
"xyz" }
   },
   cursor: {
     first:
1,
   }
 }) {
   pageInfo {
     hasNextPage
   }
   edges {
     node {
       effectiveStatus
       campaign {
         dailyBudget
       }
     }
   }
 }
}

If a promotion exists and the effectiveStatus is ACTIVE, the checkbox is checked.  Display the campaign.dailyBudget and add a link to the full Manager UI.

Alternatively, if you have the accountId, you could also use campaignConnections to fetch the campaigns and use graphQL relationships to fetch the child promotions.  This is useful in case you want to list multiple campaigns and promotions.

When a user enables a promotion in the embedded UI, below is an example GraphQL call that creates a Customer, Account, Campaign and Promotion.

mutation {
 createCustomer(input: {
   
platformId: "1",
   name:
"The customer's name.",
   timeZone: America__Los_Angeles,
   accounts: [{
     name:
"The account's name.",
     timeZone: America__Los_Angeles,
     currencyCode: USD,
     campaigns: [{
       name:
"Campaign",
       dailyBudget:
10.0,
       promotions: [{
         externalContentId:
"xyz",
       }]
     }]
   }]
 })
}

Side-Note: Customer is a wrapper around Accounts for when you want to support large ad agencies that have multiple Accounts.  For small promoters, you can name them the same thing.

Depending on the domain mapping, detect which entity levels already exist and only create certain entities.  Example, if you already have an accountId and want to create a Campaign and Promotion.

mutation {
 createCampaign(input: {
   
platformId: "1",
   customerId:
"2",
   accountId:
"3",
   name:
"Campaign",
   dailyBudget:
10.0,
   promotions: [{
     externalContentId:
"xyz",
   }]
 })
}

3. Provide a link to Promoted.ai’s branded white-label Manager UI

By default, Promoted.ai will host the full Manager UI.  We’ll host this at https://manager.promoted.ai.  To change the visible domain for your clients, create a DNS CNAME record.

See Authentication guide for how to provide a Single Sign On experience.

Manager API - Completely Native Solution

The GraphQL API that powers Promoted.ai’s Manager API can be used to construct an entirely custom, native experience for your platform’s promoters. GraphQL queries can be constructed to create, read, update, and delete data via any query that you can construct in the GraphQL language in your controller layer backend servers. Then, your controller layer servers can return a fully native response back to user clients. A completely native solution is more integration and customization work, but it can more seamlessly integrate with your existing product experience. Contact Promoted.ai for more information about this solution.

Authentication and Authorization

Our authentication can be customized depending on how your platform authenticates users (SSO, OIDC, custom, etc).

All RPCs will have basic authentication and authorization.  Our APIs will require SSL.

For Authorization, we have a concept of User and User Role.  Their descriptions will be posted to a URL for more details in the near future..

Billing

This is configurable based on the Platform.

The default setup is for Platforms to bill their customers directly.  In many cases, there is already a financial exchange happening with Promoters.  Promoted.ai will bill the platform directly.

If you want to include the billed amount in your existing bills:

query {
 tableRow(input: {
   entityLevel: CUSTOMER,
   where: {
     customer: {platformId: {is:
"1"}},
           metrics: {dateRange: {startDate:
"2020-05-01", endDate: "2020-05-30"}}
   },
   cursor: { first:
100, orderBy: "customer.customer_id", orderDirection: asc},
   includeRows:
true,
   includeTotalCount:
false
 }) {
   pageInfo {
     hasNextPage
     endCursor
   }
   edges {
     node {
       customer {
         
platformId
         customerId
         name
             }
       metrics {
         costUsdAmount
             }
     }
   }
   totalCount
 }
}

User Experience (UX)

The specific UX changes depend on the platform.  Here are some factors to think about:

Legal

Update your Terms and Conditions and Privacy Policy documents.  Promoted.ai will advise and provide examples on demand depending on the state of your current agreements and disclosures. You may already have sufficient disclosures in your legal disclosure documents and do not need to make any changes.

Sales and Services Support

Promoted.ai provides support for the continued management and scaling of your Promoted.ai powered promotion marketplace.

Administration Manager UI

Promoted.ai provides a version of the white-label promoter interface at the platform level. Using this tool, support engineering and team members can inspect promotion configurations and statistics as they appear to end-user promoters on your platform, and they can view reports about platform-level statistics across all promoters on your platform.

Seller to Promoter Conversion Features

Promoted.ai provides a variety of features and strategies to incentivize your product users to create and continue to create paid promoted contents. Contact us for more information.

Consulting and Analytics

Promoted.ai is here to help you understand, optimize, and scale your promotion system on your platform. Types of consulting that provide may include:

Page  - Promoted.ai Integration Guide