# Standalone Integration

This guide shows how to use n360ortb without an ad server by rendering ads directly from the bid response.

## Overview

In standalone mode, you:

1. Request bids using `fetchBids()`
2. Receive the winning bids as an array
3. Render ads using `n360ortb.renderAd()`

This approach is ideal for simple implementations or custom ad rendering solutions.

## Complete Example

```html
<!DOCTYPE html>
<html>
<head>
  <title>n360ortb Standalone Example</title>

  <!-- n360ortb loader -->
  <script>
  !function(){if(!window.n360ortb){window.n360ortb={init:function(){e("init",arguments)},fetchBids:function(){e("fetchBids",arguments)},setDisplayBids:function(){},targetingKeys:function(){return[]},que:[]};var n=document.createElement("script");n.async=!0,n.src="https://lib.nexx360.io/nexx360ortb/api.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(n,t)}function e(n,t){window.n360ortb.que.push([n,t])}}();
  </script>

  <script>
    // Initialize
    n360ortb.init({
      currency: 'EUR'
    });

    // Fetch bids and render
    n360ortb.fetchBids({
      slots: [
        {
          tagId: 'your-tag-id',
          slotID: 'ad-container',
          sizes: [[300, 250]]
        }
      ]
    }, function(bids) {
      // bids is an array of StoredBid objects
      if (bids.length > 0) {
        // Render each bid into its target container
        bids.forEach(function(bid) {
          n360ortb.renderAd(bid, bid.slotID);
        });
      } else {
        console.log('No bids received');
      }
    });
  </script>
</head>
<body>
  <h1>My Page</h1>

  <div id="ad-container" style="width: 300px; height: 250px;">
    <!-- Ad will render here -->
  </div>
</body>
</html>
```

## Understanding the Bid Response

The `fetchBids()` callback receives an array of `StoredBid` objects:

```javascript
[
  {
    slotID: 'ad-container',    // Target element ID
    bidId: 'abc123-def456',    // Unique bid identifier
    price: 2.50,               // Bid price
    priceBucket: '2.50',       // Price bucket for targeting
    size: '300x250',           // Size string
    adm: '<script>...</script>',  // Ad markup to render
    crid: 'creative-789',      // Creative ID
    ssp: 'appnexus',           // SSP identifier
    targeting: {...},          // Targeting key-values
    timestamp: 1706000000000,
    rawBid: {...}              // Full OpenRTB bid object
  }
]
```

The `adm` property contains the complete ad markup (HTML/JavaScript) that should be rendered.

## The renderAd() Function

`n360ortb.renderAd(bid, targetElement)` handles rendering with automatic iframe context detection:

| Context                 | Behavior                                          |
| ----------------------- | ------------------------------------------------- |
| **Main page**           | Creates an iframe and renders using `srcdoc`      |
| **Friendly iframe**     | Resizes parent iframe, then renders               |
| **SafeFrame**           | Calls `$sf.ext.expand()`, then `document.write()` |
| **Cross-origin iframe** | Sends `postMessage` resize request, then renders  |

```javascript
// Render into element by ID
n360ortb.renderAd(bid, 'ad-container');

// Render into element reference
n360ortb.renderAd(bid, document.getElementById('ad-container'));

// Render via document.write (for use inside iframe/creative)
n360ortb.renderAd(bid);
```

## Handling Multiple Slots

```javascript
n360ortb.fetchBids({
  slots: [
    {
      tagId: 'leaderboard-tag',
      slotID: 'leaderboard',
      sizes: [[728, 90], [970, 250]]
    },
    {
      tagId: 'sidebar-tag',
      slotID: 'sidebar',
      sizes: [[300, 250], [300, 600]]
    },
    {
      tagId: 'footer-tag',
      slotID: 'footer',
      sizes: [[728, 90]]
    }
  ]
}, function(bids) {
  // Render all received bids
  bids.forEach(function(bid) {
    n360ortb.renderAd(bid, bid.slotID);
  });
});
```

## Handling No Bids

When no bid is returned for a slot, you can display fallback content:

```javascript
n360ortb.fetchBids({
  slots: [
    { tagId: 'my-tag', slotID: 'ad-slot', sizes: [[300, 250]] }
  ]
}, function(bids) {
  if (bids.length > 0) {
    n360ortb.renderAd(bids[0], 'ad-slot');
  } else {
    // Show fallback
    showFallback('ad-slot');
  }
});

function showFallback(slotID) {
  var container = document.getElementById(slotID);
  container.innerHTML = '<img src="/fallback-banner.jpg" alt="Advertisement">';
}
```

## How renderAd() Works

The built-in `n360ortb.renderAd()` function automatically:

1. **Creates a secure iframe** - Ads are isolated in their own document context
2. **Uses `srcdoc`** - Modern, secure way to inject HTML into iframes
3. **Handles resizing** - Automatically resizes based on bid dimensions
4. **Detects context** - Adapts behavior for SafeFrame, friendly iframe, or cross-origin scenarios

{% hint style="success" %}
Using the built-in `renderAd()` is recommended over custom implementations as it handles edge cases and different iframe contexts automatically.
{% endhint %}

## Refreshing Ads

To refresh ads after a period of time:

```javascript
function refreshAds() {
  // Fetch new bids and render (renderAd clears the container automatically)
  n360ortb.fetchBids({
    slots: [
      { tagId: 'your-tag-id', slotID: 'ad-container', sizes: [[300, 250]] }
    ]
  }, function(bids) {
    if (bids.length > 0) {
      n360ortb.renderAd(bids[0], 'ad-container');
    }
  });
}

// Refresh every 30 seconds
setInterval(refreshAds, 30000);
```

{% hint style="warning" %}
Be mindful of refresh rates. Excessive ad refreshing can negatively impact user experience and may violate SSP policies.
{% endhint %}

## Next Steps

* [API Reference](/integration-methods/direct-integration-n360ortb/api-reference.md) - Complete API documentation
* [GAM Integration](/integration-methods/direct-integration-n360ortb/gam-integration.md) - For integration with Google Ad Manager
* [Privacy & Consent](/integration-methods/direct-integration-n360ortb/privacy-consent.md) - Handle GDPR and other privacy requirements


---

# 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/standalone-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.
