# Native Ads

The `n360ortb` library supports **OpenRTB 1.2 native impressions** alongside banner and video. Native ads are configured on a per-slot basis by adding a `native` block to the slot definition, and the library returns the parsed native response on the bid so you can either:

1. Render the ad yourself in the publisher page (asset-based DOM rendering), or
2. Serve it through Google Ad Manager using native targeting keys + a template creative.

{% hint style="info" %}
Native support was introduced in n360ortb **v0.3.0**. The library is served from `https://lib.nexx360.io/nexx360ortb/api.js`.
{% endhint %}

## Slot Configuration

Native slots accept either a Prebid-style shortcut config or a raw OpenRTB 1.2 passthrough.

### Prebid-style shortcuts (recommended)

```javascript
n360ortb.fetchBids({
  slots: [{
    slotID: 'native-slot-1',
    tagId: 'your-tag-id',
    mediaType: 'native',
    native: {
      title:       { required: true,  len: 80 },
      image:       { required: true,  sizes: [300, 250] },
      icon:        { required: false, sizes: [50, 50] },
      sponsoredBy: { required: true },
      body:        { required: false, len: 200 },
      cta:         { required: true },
      rating:      { required: false }
    }
  }]
}, renderCallback);
```

| Shortcut      | Required flag     | Maps to OpenRTB asset                                                     |
| ------------- | ----------------- | ------------------------------------------------------------------------- |
| `title`       | `required`        | `{ title: { len } }` (defaults to 140 chars)                              |
| `image`       | `required`        | `{ img: { type: 3 (main), w, h } }` — or `wmin/hmin` with `aspect_ratios` |
| `icon`        | `required`        | `{ img: { type: 1 (icon), w, h } }`                                       |
| `sponsoredBy` | `required`        | `{ data: { type: 1 } }` (brand name)                                      |
| `body`        | `required`, `len` | `{ data: { type: 2 } }` (description)                                     |
| `rating`      | `required`        | `{ data: { type: 3 } }`                                                   |
| `cta`         | `required`        | `{ data: { type: 12 } }` (call-to-action text)                            |
| `clickUrl`    | `required`        | *Not a request asset — returned on `link.url`.*                           |

### OpenRTB 1.2 passthrough

If you need full control (event trackers, context/placement type, video assets, custom `ext`), pass the OpenRTB request directly:

```javascript
n360ortb.fetchBids({
  slots: [{
    slotID: 'native-slot-1',
    tagId: 'your-tag-id',
    mediaType: 'native',
    native: {
      ortb: {
        ver: '1.2',
        context: 1,
        plcmttype: 1,
        assets: [
          { id: 1, required: 1, title: { len: 80 } },
          { id: 2, required: 1, img: { type: 3, w: 300, h: 250 } },
          { id: 3, required: 1, data: { type: 1 } },
          { id: 4, required: 0, data: { type: 2 } },
          { id: 5, required: 1, data: { type: 12 } }
        ]
      }
    }
  }]
}, renderCallback);
```

See the [Native Configs](/integration-methods/native/native-configs.md) page for pre-defined configurations (`native_config=1`, `native_config=2`) that you can reuse.

{% hint style="info" %}
Set `mediaType: 'native'` to tell the library the slot is native-only. Without it the library assumes a banner slot and requires `sizes`.
{% endhint %}

## Bid Response

When a native bid wins, the library parses the native response out of `bid.adm` (a stringified JSON payload) and exposes it on the returned `StoredBid`:

```typescript
interface StoredBid {
  // ...common fields (slotID, bidId, price, priceBucket, crid, ssp, ...)
  mediaType: 'banner' | 'video' | 'native';
  nativeResponse?: NativeResponse;     // Present when mediaType === 'native'
  adm: string;                         // Raw stringified native response
  targeting: Record<string, string>;   // Includes native_* keys (see below)
}

interface NativeResponse {
  ver?: string;
  assets?: Array<{
    id: number;
    title?: { text: string };
    img?:   { type?: number; url: string; w?: number; h?: number };
    data?:  { type?: number; value: string };
  }>;
  link: { url: string; clicktrackers?: string[] };
  imptrackers?: string[];
  eventtrackers?: Array<{ event: number; method: number; url?: string }>;
  jstracker?: string;
}
```

Media type is detected from `bid.ext.mtype` when present (1=banner, 2=video, 4=native), with fallback to JSON-shape probing and VAST sniffing.

## Rendering in the Publisher Page

```javascript
n360ortb.fetchBids({
  slots: [/* native slot config */]
}, function (bids) {
  bids.forEach(function (bid) {
    if (bid.mediaType !== 'native' || !bid.nativeResponse) return;

    var nr    = bid.nativeResponse;
    var title = nr.assets.find(function (a) { return a.title; });
    var image = nr.assets.find(function (a) { return a.img  && a.img.type  === 3; });
    var brand = nr.assets.find(function (a) { return a.data && a.data.type === 1; });
    var body  = nr.assets.find(function (a) { return a.data && a.data.type === 2; });
    var cta   = nr.assets.find(function (a) { return a.data && a.data.type === 12; });

    var slot = document.getElementById(bid.slotID);
    slot.innerHTML =
      '<a href="' + nr.link.url + '" target="_blank" rel="noopener">' +
        (image ? '<img src="' + image.img.url + '">' : '') +
        (brand ? '<div class="sponsor">' + brand.data.value + '</div>' : '') +
        (title ? '<h3>'  + title.title.text + '</h3>' : '') +
        (body  ? '<p>'   + body.data.value  + '</p>'  : '') +
        (cta   ? '<button>' + cta.data.value + '</button>' : '') +
      '</a>';

    // IMPORTANT: fire impression + event trackers
    (nr.imptrackers   || []).forEach(function (u)  { new Image().src = u; });
    (nr.eventtrackers || []).forEach(function (et) {
      if (et.method === 1 && et.url) new Image().src = et.url;
    });
  });
});
```

{% hint style="warning" %}
You **must** fire the impression trackers (`nr.imptrackers` and image-method `nr.eventtrackers`) when the ad becomes viewable, otherwise the SSP will not record the impression and you will not be paid.
{% endhint %}

## Rendering through Google Ad Manager

For GAM-served natives, the library exposes the winning native assets as targeting key-values so your GAM native creative template can reference them via macros.

### Native targeting keys

Set only when the winning bid is native. Values longer than 200 chars are replaced with the `bidId` (sendId pattern) — the creative resolves the full value via the library's `__n360_locator__` postMessage path.

| Key                   | Source                                                        |
| --------------------- | ------------------------------------------------------------- |
| `n360_mt`             | Media type: `banner`, `video`, or `native`                    |
| `n360_native_title`   | `assets[].title.text` (truncated to 140 chars)                |
| `n360_native_image`   | `assets[].img.url` where `type=3` (main image)                |
| `n360_native_icon`    | `assets[].img.url` where `type=1` (icon)                      |
| `n360_native_brand`   | `assets[].data.value` where `type=1` (sponsored by)           |
| `n360_native_body`    | `assets[].data.value` where `type=2` (description, truncated) |
| `n360_native_rating`  | `assets[].data.value` where `type=3`                          |
| `n360_native_cta`     | `assets[].data.value` where `type=12`                         |
| `n360_native_linkurl` | `link.url`                                                    |

### GAM setup

1. Create a **Native ad format** in GAM matching the fields above (title, image, brand, body, CTA, clickUrl).
2. In your native creative, bind each variable to the corresponding `n360_native_*` key-value (e.g. `%%PATTERN:n360_native_title%%`).
3. Target line items on `n360_mt = native` AND `n360_pb >= <your-price-bucket>`.
4. Standard line-item / price-bucket setup follows the same pattern as banner — see [Line Item Setup](/integration-methods/direct-integration-n360ortb/gam-integration/line-item-setup.md).

See [GAM Creative Setup](/integration-methods/direct-integration-n360ortb/gam-integration/gam-creative-setup.md) for the general pattern of binding `n360_*` keys to creative macros.

## Complete Example

```html
<!DOCTYPE html>
<html>
<head>
  <title>n360ortb - Native Example</title>

  <!-- n360ortb async stub -->
  <script>
  !function(n,w,d,s,u,N,g){if(w[n])return;function q(m,a){w[n]._Q.push([m,a])}
  w[n]={init:function(){q("init",arguments)},fetchBids:function(){q("fetchBids",arguments)},
  setDisplayBids:function(){},clearDisplayBids:function(){},targetingKeys:function(){return[]},
  bids:function(){return[]},getBid:function(){return null},debug:function(){},_Q:[]};
  N=d.createElement(s);N.async=1;N.src=u;g=d.getElementsByTagName(s)[0];
  g.parentNode.insertBefore(N,g)}("n360ortb",window,document,"script","https://lib.nexx360.io/nexx360ortb/api.js");

  n360ortb.init({ currency: 'EUR', bidTimeout: 3000 });

  n360ortb.fetchBids({
    slots: [{
      slotID: 'native-slot-1',
      tagId: 'your-tag-id',
      mediaType: 'native',
      native: {
        title:       { required: true,  len: 80 },
        image:       { required: true,  sizes: [300, 250] },
        sponsoredBy: { required: true },
        body:        { required: false, len: 200 },
        cta:         { required: true }
      }
    }]
  }, function (bids) {
    bids.forEach(renderNative);
  });

  function renderNative(bid) {
    if (bid.mediaType !== 'native' || !bid.nativeResponse) return;
    var nr = bid.nativeResponse;
    // ... build DOM from nr.assets and fire nr.imptrackers
  }
  </script>
</head>
<body>
  <div id="native-slot-1"></div>
</body>
</html>
```

## Related

* [Native Configs](/integration-methods/native/native-configs.md) — reusable OpenRTB 1.2 configurations
* [API Reference](/integration-methods/direct-integration-n360ortb/api-reference.md) — full `n360ortb` API
* [GAM Creative Setup](/integration-methods/direct-integration-n360ortb/gam-integration/gam-creative-setup.md) — generic GAM targeting setup


---

# 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://developer.nexx360.io/integration-methods/direct-integration-n360ortb/native-integration.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.
