> ## Documentation Index
> Fetch the complete documentation index at: https://docs.refmatter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scan a competitor's content

> Find an advertiser, confirm its social accounts, compare public content, and import the strongest candidates.

A marketing tool can build a competitor scan from Refmatter's search, account, list, and import endpoints. This recipe starts with a Meta Ad Library advertiser, checks the advertiser's public profiles, collects candidates from each platform, ranks them in your own code, and imports the items worth keeping.

## 1. Find the advertiser

Search the Meta Ad Library by the name the user supplies. The SDK sets `type=accounts`; the REST request states it explicitly.

<CodeGroup>
  ```bash curl theme={null}
  curl -G https://api.refmatter.com/v1/search \
    -H "Authorization: Bearer $REFMATTER_API_KEY" \
    --data-urlencode "platform=meta_ad_library" \
    --data-urlencode "type=accounts" \
    --data-urlencode "q=Dot & Key"
  ```

  ```ts TypeScript theme={null}
  const advertisers = await refmatter.search.accounts({
    platform: 'meta_ad_library',
    q: 'Dot & Key',
  });

  const advertiser = advertisers.data[0];
  if (!advertiser) throw new Error('No advertiser found');
  ```
</CodeGroup>

Pick a result row and keep its `id`. The row carries `name`, `meta_ad_library.category`, `stats.followers` (the Meta page like count), and `meta_ad_library.instagramHandle`.

```json theme={null}
{
  "object": "account",
  "id": "meta_ad_library:100200300400500",
  "platform": "meta_ad_library",
  "handle": "dotandkey",
  "name": "Dot & Key",
  "url": "https://www.facebook.com/ads/library/?view_all_page_id=100200300400500",
  "description": null,
  "avatar": [],
  "verified": true,
  "stats": { "followers": 412903 },
  "meta_ad_library": {
    "category": "Beauty, cosmetic & personal care",
    "likes": 412903,
    "instagramHandle": "dotandkey.skincare",
    "instagramFollowers": 688400,
    "instagramVerified": true,
    "pageDeleted": false
  }
}
```

## 2. Confirm the social accounts

Look up Instagram, TikTok, and YouTube separately. Use `meta_ad_library.instagramHandle` for Instagram. TikTok and YouTube need a handle the user already has; the Ad Library result does not carry those handles.

<CodeGroup>
  ```bash curl theme={null}
  curl -G https://api.refmatter.com/v1/accounts/lookup \
    -H "Authorization: Bearer $REFMATTER_API_KEY" \
    --data-urlencode "platform=instagram" \
    --data-urlencode "handle=dotandkey.skincare"

  curl -G https://api.refmatter.com/v1/accounts/lookup \
    -H "Authorization: Bearer $REFMATTER_API_KEY" \
    --data-urlencode "platform=tiktok" \
    --data-urlencode "handle=dotandkey"

  curl -G https://api.refmatter.com/v1/accounts/lookup \
    -H "Authorization: Bearer $REFMATTER_API_KEY" \
    --data-urlencode "platform=youtube" \
    --data-urlencode "handle=NASA"
  ```

  ```ts TypeScript theme={null}
  const instagram = await refmatter.accounts.lookup({
    platform: 'instagram',
    handle: advertiser.meta_ad_library!.instagramHandle!,
  });
  const tiktok = await refmatter.accounts.lookup({
    platform: 'tiktok',
    handle: 'dotandkey',
  });
  const youtube = await refmatter.accounts.lookup({
    platform: 'youtube',
    handle: '@NASA',
  });
  ```
</CodeGroup>

Instagram and TikTok publish no anonymous account search. `accounts.lookup` works by a known handle, URL, or id, so the handle must come from the advertiser row or the user; never guess one. The account response includes the platform's public profile data, such as `name`, `description`, `url`, `avatar`, `verified`, and `stats`. Platform-specific blocks add the fields that platform publishes: for example, Instagram has `instagram.private`, while TikTok has `tiktok.likes` and `tiktok.private`. See [Look up an account](/guides/look-up-an-account) for the full response fields and platform differences.

## 3. Collect candidates

List each account with the platform-specific selector. The advertiser id is the selector for the Meta page.

For the Meta page, request active ads. Each row can represent a near-identical variant group; `ad.collationCount` tells you how many variants are in that group. If `total` is large, split the request into ad start-date windows with `since` and `until`.

```ts TypeScript theme={null}
const ads = await refmatter.items.list({
  account: advertiser.id,
  status: 'active',
});
```

For Instagram, make two list calls: reels for engagement counts and posts for captions. Instagram returns 12 rows per page.

```ts TypeScript theme={null}
const reels = await refmatter.items.list({
  account: 'instagram:@dotandkey.skincare',
  type: 'reels',
});
const posts = await refmatter.items.list({
  account: 'instagram:@dotandkey.skincare',
  type: 'posts',
});
```

For TikTok, the list is the 10 newest videos and has no cursor. For YouTube, ask for popular items and follow its cursor.

```ts TypeScript theme={null}
const tiktok = await refmatter.items.list({ account: 'tiktok:@dotandkey' });
const youtube = await refmatter.items.list({
  account: 'youtube:@NASA',
  sort: 'popular',
});

const moreYoutube =
  youtube.page.nextCursor === null
    ? null
    : await refmatter.items.list({ cursor: youtube.page.nextCursor });
```

The same cursor rule applies to Instagram and YouTube: pass `page.nextCursor` as `cursor` alone. The cursor already carries the platform, account, and filters, so do not repeat `account`, `type`, `sort`, or other filters on the next call. TikTok and the Ad Library have no cursor. See [List an account's items](/guides/list-items) for the complete paging rules and response fields.

## 4. Rank candidates in your code

Refmatter returns candidates; it does not rank them for you. Build a score that fits the product's goal from the fields available on each platform:

* Use `stats.views`, `stats.likes`, and `stats.comments` where the platform provides them. Instagram reels provide those engagement fields; YouTube provides views; TikTok provides a view count but its item rows do not provide likes or comments.
* Use `ad.startedAt`, `ad.endedAt`, and `ad.collationCount` to compare active periods and the number of near-identical ad variants. Ad Library rows do not provide public engagement counts.
* Use `publishedAt` and `publishedText` where present. Several values are `null`: list rows normally have `publishedAt: null` for YouTube, Instagram does not provide `publishedText`, and TikTok does not provide `publishedText`.
* Keep the platform's `null` values as unknown rather than treating them as zero. The [item list guide](/guides/list-items) describes what each platform provides and omits.

For example, a score can combine views and likes for Instagram reels, views and `publishedText` for YouTube, views and recency for TikTok, and start date plus `ad.collationCount` for Meta ads. The weights and the treatment of missing values belong in your application.

## 5. Import the chosen items

Import each selected row's `url`. Use `imports.create` when you want to manage the import job yourself, or use the SDK's `importUrl` convenience wrapper to create the import and wait for its reference.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.refmatter.com/v1/imports \
    -H "Authorization: Bearer $REFMATTER_API_KEY" \
    -H "Idempotency-Key: competitor-scan-dot-key-001" \
    -H "Content-Type: application/json" \
    -d '{"url":"https://www.youtube.com/watch?v=21X5lGlDOfg","mediaProfile":"full"}'
  ```

  ```ts TypeScript theme={null}
  const { importJob, reference } = await refmatter.importUrl(selected.url, {
    waitFor: 'reference',
  });
  if (reference === null) {
    throw new Error(`${importJob.outcomeCode}: ${importJob.outcomeMessage}`);
  }

  const savedReference = await refmatter.references.get(reference.id);
  if (savedReference.primaryMediaId !== null) {
    const media = await refmatter.media.access(savedReference.primaryMediaId);
    console.log(media.downloadUrl);
  }
  ```
</CodeGroup>

The REST import returns an `id` and, once the reference is readable, a `referenceId`. Read that reference with `GET /v1/references/{referenceId}`. In the SDK, `importUrl` returns `{ importJob, reference }`; `reference` is `null` when the import failed before a reference existed. Use `primaryMediaId` with `GET /v1/media/{mediaId}/download-url` or `refmatter.media.access(mediaId)` for a media download URL. See [Import a URL](/guides/import-a-url), [References](/concepts/references), and [Media access](/guides/media-access).

```json theme={null}
{
  "mediaId": "01a0a04b-0000-4000-8000-000000000001",
  "downloadUrl": "https://r2.cloudflarestorage.com/refmatter/01a0a04b-0000-4000-8000-000000000001?X-Amz-Signature=example",
  "expiresAt": "2026-09-14T14:27:00.000Z",
  "contentType": "video/mp4",
  "filename": "21X5lGlDOfg.mp4"
}
```

## 6. Budget the scan

Plan roughly one credit for each live page that has at least one row, or for the first stored serving of a page with a row. Repeats within `maxAge` are free, empty pages are free, and every error is free. That means the scan can usually reuse a fresh advertiser search, account lookup, or item page without charging again; the two Instagram list types are separate pages. See [Search](/guides/search), [Look up an account](/guides/look-up-an-account), and [List an account's items](/guides/list-items) for the endpoint-specific credit rules.

Every response includes `Refmatter-Credits-Remaining`, the workspace balance after the response. A live request at a zero balance returns `402 insufficient_credits`. If the service returns `429 rate_limited`, use the `Retry-After` header before trying again. Errors do not charge credits.

## Not in this endpoint

This recipe does not provide private account data, anonymous Instagram or TikTok account search, public engagement counts that a platform does not publish, or a server-side ranking. It also does not import every row automatically: choose the candidates in your own code and import only the URLs your workflow needs.

## Next steps

* [Search](/guides/search)
* [Look up an account](/guides/look-up-an-account)
* [List an account's items](/guides/list-items)
* [Import a URL](/guides/import-a-url)
* [Media access](/guides/media-access)
