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.

✴️ 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.