1. Help Center
  2. RevContent Native API

Creating Custom API Widgets

Our API enables you to retrieve the same ad fill you'd see in our traditional widgets but in a much more customizable format. 

NOTE: API usage requires full Advertising Disclosure.

API REQUESTS

  • Content type:
application/json or text/xml
  • Endpoint:
GET http://trends.revcontent.com/api/v2/

 

⚠️ REQUIRED PARAMETERS

  Parameter      Type   Default                                   Description
api_key
   string     none Your account's API key
pub_id
   integer     none Your account ID
widget_id
   integer     none The ID of the widget associated with the request
domain
   string     none The URL encoded domain name associated with the widget

Sample Request:

https://trends.revcontent.com/api/v2/?api_key={Insert_Your_API_Key}&pub_id={Insert_Your_Account_ID}&widget_id={Insert_Your_Widgets_ID}&domain={Insert_Your_Widgets_Domain}

 

ℹ️ OPTIONAL PARAMETERS

        Parameter    Type Default                                    Description
user_ip
   string request IP End user's IP address. Responses are tailored to end user's location. If an IP is not provided, the request IP is used. If you're calling the API with client-side code such as Javascript, we can detect the user's IP. Otherwise you'll need to pass it. 
user_agent
   string request UA End user's user agent (UA). Used to segment stats by device type. If a UA is not provided, the request UA is used. If you're calling the API with client-side code such as Javascript, we can detect the user's UA. Otherwise you'll need to pass it. This value must be URL-encoded into valid ASCII format 
referrer
   string   none End user's encoded page URL the request is being made from 
width
  integer    1280 End user's screen width
img_w
  integer     400

Creative image width. Options are:

  • 125 (extra small)
  • 225 (small)
  • 300 (medium)
  • 400 (large)

If a different width outside of these four options is specified, the closest will automatically be applied

img_h
  integer     315

Creative image height. Options are:

  • 94 (extra small)
  • 150 (small)
  • 225 (medium)
  • 315 (large)

If a different height outside of these four options is specified, the closest will automatically be applied

format
   string   JSON Request response format
sponsored_count
  integer     25 Number of sponsored creatives you'd like returned in the response
sponsored_offset 
  integer      0 Position you'd like the sponsored creative response to start from
internal_count
  integer      5 Number of internal creatives you'd like returned in the response
internal_offset
  integer      0 Position you'd like the internal creative response to start from
send_view
   string    none Used to register widget and creative views. Pass "send_view=true" to return view hashes. See the "Tracking Views" section below for detailed setup instructions 
tracking
   string    auto

Used to manually register all impressions. By default "tracking=auto" is passed and impressions are automatically registered. If "tracking=manual" is passed, an impression will not be registered until the impression string is posted back to http://trends.revcontent.com/api/v2/track.php as the "d" value:
"d={long_impression_string}"

✴️ pick_one
   string       1 If "tracking=manual" is being used and you’d like to only register impressions on certain creatives, the “pick_one” parameter can be passed. By passing “pick_one=1”, each creative will have an “impression” hash. You’re able to use this as an impression tracking pixel when calling http://trends.revcontent.com/api/v2/track.php. Each creative and subsequent click link would be “position=1”.
✴️ tracking_method
   string   none If "tracking=manual" is being used and you’d like an impression GET URL instead of a POST URL you can pass "tracking_method=get"
us_privacy
   string   none Used to pass IAB CCPA URL-encoded
URL-encoded US Privacy string
gdpr
   string   none Used to indicate current impressions is a GDPR regulated impressions.
`0` GDPR does not apply; `1` GDPR applies. 
gdpr_consent
   string   none Used to pass the URL-safe base64-encoded IAB GDPR Transparency & Consent string.
Only meaningful if gdpr=1
gpp
   string   none Used to pass url-safe base64-encoded IAB GPP consent string
gpp_sid
   string   none

Used to pass GPP section ID(s) in force for the current transaction. In most cases, this field should have a single section ID. In rare occasions where such a single section ID can not be determined, the field may contain up to 2 values, separated by a comma.

revsub[]=
   string   none

Used to pass subIDs in order to achieve customized reporting. 

Example: 

&revsub[taco]=truck

✴️ only applicable if "tracking=manual" is being used

 


 

API RESPONSES

    Parameter

                                                      Description

headline

Creative headline

url

Creative click URL

image

Creative image URL

brand

Creative provider

content_type

Creative content type - article or video

type

Creative type - sponsored or internal

uid

Creative type and unique identifier (type_uid)

target_url

Creative destination URL

view

Request to be made once the creative enters a user's viewport. See the "Tracking Views" section below for detailed instructions

impression

Encoded impression string. Only returned if "tracking=manual" and "pick_one=1" are being passed into the request

Sample Response

{"content":[{"headline":"Sample Headline","url":"https:\/\/trends.revcontent.com\/click.php?d=FGEvEC23O7thB%2Bc%2FbvyqPZRuPR%2BkEr4UOIDs0NqONIC5NzY13LWWNnbW4XYf%2F2HUblhFr63pVKst6%2F1rBDoNCwDkSkhJcgx3wJgy6AB%2FrugEW6QGB3PMJxBUPxgXWZEXIDfwwbMFbl6BxJc2GDHHtsy3anBb7XKDT3jkC3Ekut8Q5ev5oOovH1WEjCLYRqqV2B7Caqz5rl%2FKuTBCBtkd6qN4Ie2jmU8OmzVoRTpo2Xp09u645olzuzrWIxFeob8my9Qs9CKLCY%2Bt3CeiFJVCq9wP8rHglUEY5G9y%2BnjKHxOcUlcumprWWWDbiqUwYqGLxHWDLlz%2BnooR2RMgvTaoKcV8B9oz0UqxCseZsMdcL6bQyvd0VPHsyuaJlMoanG27EBWry6QYLOHd%2FlQV3aaBvSaR00J2FNBMF8zAdmBEvUs1dejPrT15oynoDZNUYu%2F9%2FIbmKDT5owLdrAPVoXEQKzKT9RAFwJiiOsCPNDwQv4CiKPyg4Uk%2Bv1UKsTD%2FXjJ597exjZr%2FYIs7OqPZlg%2Bl%2Fxm%2FK5qXKYY%2B9UCmKgXv0dScAK4XSi8HK7Zk6Yb7QYbYAtHx%2Bn5FXp3Fa1CAcNH7DHcM4%2FfkMn3zUmT5n08TG5roBsekEHFmB%2FMn%2Fqr9f5lKSYWbKhxTak3Vz%2BGAzpooZv5sH4p65C9ov%2BenOAg0KlXwguJ0RfIEwRtqZkoK5FQ3SUWq1Aeb57sfds5MrvqBMPRDvRuCneybbohbqFpiudL4v59DmgqixQ%2BWdAtANk5yHo2OxsjasZLBBfSzdTuGGaJ3tKvgdOBRCQeTXXim29ihMzIQl6HK9AIr1Ioxa2dlU1hwozTVvN20gxcEPfuoWmuE7ISpJz38uju1Mwys%2BSNMMP1lZ391pGyMgGWFQCK1fhrkqOLsrz5fh%2FVBMBf0EWunHp1PfOLGa5QmlBRevdLCpo1NUWY%2Fnx5CHIiLWqz4BurfDs6daqjv3gsdQVwmIHcUD5d6R9gj2ped7szkXq6ckfYF4LonQRqbNNALF6a8wr3BWaLJfGbEGM89BoTh3IzHiigfRGUjaseLaATtet1Wex8o7FUgsEX1XNBbWlyWtujNJwRCPfN57%2FJT%2FGv97qAj90haJhFhtMvAP%2FypIWCqnu7NH6NX8irQM4exWJta&s2s=1","image":"https:\/\/images.revcontent.com\/revcontent\/image\/fetch\/f_auto,h_315,w_420,c_fill,g_face\/pg_1\/https:\/\/revcontent-p0.s3.amazonaws.com\/content\/images\/12345-67890.jpg","brand":"Revcontent","type":"sponsored","uid":"sponsored_123456","target_url":"https:\/\/example.com\/123?","impression":""}],"impression":""}

 


 

Tracking Views

Views should always be tracked. A view occurs when a widget and its creative(s) enter the user's viewport. The "send_view" parameter is used to generate a view hash. By passing "send_view=true" into your request, a view parameter will be returned in your response with a unique hash as the value. To record the view, you'll need to post back the view hash returned in the response to https://trends.revcontent.com/view.php. The "view" parameter also accepts 2 additional parameters:

  1. view_type - the type of view event. Either "widget" or "fill"
  2. p[] - the creative's panel position index starting from "0"

    Sample Post Body

    {"view":"View_Hash_Goes_Here","view_type":"fill","p[]":"0"} 


    In order to determine which elements have entered a user's viewport and are considered viewed, we recommend using something like the Intersection Observer API.

    The following is an example of the entire view tracking process setup in Javascript:

    const settings = {
    url: '//trends.revcontent.com/api/v2/',
    widgetId: {Your_Widgets_ID},
    apiKey: '{Your_API_Key}',
    pubId: {Your_Account_ID},
    domain: '{Your_Widgets_Domain}',
    sponsoredOffset: 0,
    sponsoredCount: 4
    };

    const widgetData = {
    items: [],
    view: '',
    queue: [],
    widgetView: false
    };

    const observerOptions = {
    threshold: 0.95
    };


    const createItem = (item, index) => document.createRange().createContextualFragment(`
    <div class="rc-item" data-index="${index}">
    <a href="${item.url}">
    <div>
    <img src="${item.image}" />
    <h3>${item.headline}</h3>
    </div>
    </a>
    </div>
    `);



    const buildWidget = async () => {

    const data = await fetch('${settings.url}?api_key=${settings.apiKey}&pub_id=${settings.pubId}&domain=${settings.domain}&widget_id=${settings.widgetId}&sponsored_count=${settings.sponsoredCount}&sponsored_offset=${settings.sponsoredOffset}&send_view=true`, {
    credentials: 'include'
    }).then(res => res.json());

    widgetData.items = data.content;
    widgetData.view = data.view;
    widgetData.impression = data.impression;

    const target = document.getElementById('app');

    if (target) {
    widgetData.items?.forEach((item, index) => target.appendChild(createItem(item, index)));
    }

    // Ideally, delay observation for a moment until html is rendered. Intersection Observer will trigger
    // as true when the element is first created if in the view port. This delay gives your ad panel a chance
    // to generate the markup before observation.
    setTimeout(() => {
    createObserver();
    }, 150);
    }

    // Call the view event
    const trackView = () => {

    // Only fire an event if the queue has items. If not, do nothing.
    if (widgetData.queue.length > 0) {


    // Create a search params and append data to it. The view payload expects the following:
    // view: The view hash received from the API. This requires decoding via decodeURIComponent
    // p[]: The index to be tracked as viewed. This can be multiple entries of an index such as
    // p[]: 0
    // p[]: 1
    // p[]: 2
    const data = new URLSearchParams();
    data.append('view', decodeURIComponent(widgetData.view));

    if (!widgetData.widgetView) {
    widgetData.widgetView = true;
    data.append('view_type', 'widget');
    }
    else {
    data.append('view_type', 'fill');
    }

    widgetData.queue.forEach(entry => {
    data.append('p[]', entry);
    })

    // Once the data is added to the search params, perform a post. This must be
    // form encoded as shown here, with the search params being sent as the body
    // of the request. This will return 200 for successful calls.
    fetch(`https://trends.revcontent.com/view.php`, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    body: data
    })

    // Clear the queue, the items currently in the queue have been tracked and
    // can be removed.
    widgetData.queue = [];
    }
    }

    // This is the callback that is ran whenever an element is observed.
    const onIntersection = (entries, observer) => {
    entries.forEach(entry => {
    if (entry.intersectionRatio >= observerOptions.threshold) {
    // If this is hit, it means the element meets the intersection ratio value
    // The ratio is a percentage between 0 and 1 with 1 being 100% in view. Push
    // the index into the queue in preparation of sending a view event.
    widgetData.queue.push(parseInt(entry.target.dataset.index, 10));

    // The position has been queue for a view event and we no longer need to observe
    // this element. Remove it from observation.
    observer.unobserve(entry.target);

    // Delay firing the event briefly. This gives your observer a chance to aggregate
    // indexes into the queue before firing an event. For example, if the first and
    // second panel are in view at the same time, you can send them as a single event
    // with the payload holding the indexes for each.
    setTimeout(() => {
    trackView();
    }, 50);
    }
    })
    }

    // Create a observer and then query the DOM to get the elements to watch.
    const createObserver = () => {
    const observer = new IntersectionObserver(onIntersection, observerOptions);

    // Get the elements to observe via a class name. Set this to whatever is appropriate.
    const elements = document.querySelectorAll('.rc-item');

    // If any elements are found, iterate and observe them.
    if (elements) {
    elements.forEach(element => observer.observe(element));
    }
    }


    buildWidget();

    If running multiple widget placements, treat them each as independents when it comes to tracking views. For example, if you have two spots on a page where the API is showing ads, each of them should be treated as their own unique widget and will need to be managed as such for the view tracking logic. We track views via an index which represents the position of the ad in regards to where it's displayed for that batch of items. Each ad shown is its own panel with an index of 0 (the very first ad shown in that group of ads) to whatever the amount of items requested is (0/1/2/3 for 4 sponsored items, etc). In other words, you might have 2 places where you want to show results from the API. That would essentially give you the following:

    Placement 1 (4 sponsored items requested)

    • Panel indexes: 0/1/2/3
    • View hash: (unique hash sent back from request)
    • Unique queue for this placement: (empty array on initialization, will hold indexes of items queued for view event)


    Placement 2 (another 4 sponsored items requested)

    • Panel indexes: 0/1/2/3
    • View hash: (unique hash sent back from request)
    • Unique queue for this placement: (empty array on initialization, will hold indexes of items queued for view event)

    Then, in the observer/view tracking logic:

    1. determine which placement it is
    2. push it to the appropriate queue
    3. get the hash for that queue
    4. fire the event
    5. then clear the appropriate queue for the placement.

    You may not require this behavior depending on your needs, but it's something to consider.