@saltcorn/meta-marketing-api 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -0
- package/api.js +613 -1
- package/index.js +73 -0
- package/package.json +1 -1
- package/tests/api.test.js +223 -0
- package/tests/media.test.js +291 -0
package/README.md
CHANGED
|
@@ -133,6 +133,13 @@ a different token.
|
|
|
133
133
|
| `get_meta_ad(adId, query)` | One ad |
|
|
134
134
|
| `get_meta_ad_creatives(accountId, query)` | The creatives in an ad account |
|
|
135
135
|
| `get_meta_ad_creative(creativeId, query)` | One creative |
|
|
136
|
+
| `get_meta_ad_headline(ad)` | The headline of an ad, from an ad id or an ad you have already read |
|
|
137
|
+
| `get_meta_ad_body(ad)` | The primary text of an ad: the longer wording above the image |
|
|
138
|
+
| `get_meta_ad_text(ad)` | Both of the above together, as `{ headline, body }`, in one read |
|
|
139
|
+
| `get_meta_ad_media(ad, options)` | What an ad is made of and where to download it |
|
|
140
|
+
| `get_meta_ad_media_type(ad)` | Whether an ad is an `image`, a `video`, `mixed` or `unknown` |
|
|
141
|
+
| `get_meta_ad_media_url(ad)` | The address of the picture or the film in an ad |
|
|
142
|
+
| `get_meta_page_access_token(pageId)` | A token for one of your pages, or nothing when you have no access to it |
|
|
136
143
|
| `get_meta_ad_preview(adId, adFormat)` | A ready made HTML preview of an ad |
|
|
137
144
|
| `get_meta_insights(objectId, query)` | Performance figures for an account, campaign, ad set or ad |
|
|
138
145
|
| `get_meta_insights_async(objectId, query)` | The same, run as a background report, for large date ranges |
|
|
@@ -164,6 +171,159 @@ get_meta_ads("", {
|
|
|
164
171
|
})
|
|
165
172
|
```
|
|
166
173
|
|
|
174
|
+
The wording of an ad is not in the ad itself, it sits on the creative, and
|
|
175
|
+
Meta keeps it in a different place for each kind of ad. `get_meta_ad_text`
|
|
176
|
+
finds it for you, wherever it is:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
get_meta_ad_text(ad_id)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
which gives you `{ headline: "...", body: "..." }`, where the body is the
|
|
183
|
+
longer text above the image. For an ad that is boosting a post already on
|
|
184
|
+
your page, the wording belongs to the post rather than to the ad; the module
|
|
185
|
+
asks Meta for a token for that page and reads it with that, which needs the
|
|
186
|
+
access token in the settings to have a say over the page, as described under
|
|
187
|
+
*Ads that boost a post on your page* below. When it cannot be read you get
|
|
188
|
+
empty text back rather than an error; `get_meta_ad_preview` will still show
|
|
189
|
+
you the ad as it appears.
|
|
190
|
+
|
|
191
|
+
### The picture or the film in an ad
|
|
192
|
+
|
|
193
|
+
`get_meta_ad_media` tells you what kind of ad you are looking at and where to
|
|
194
|
+
download the file it is built on:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
get_meta_ad_media(ad_id)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
gives you
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
{
|
|
204
|
+
type: "video",
|
|
205
|
+
carousel: false,
|
|
206
|
+
media: [
|
|
207
|
+
{
|
|
208
|
+
kind: "video",
|
|
209
|
+
video_id: "1234",
|
|
210
|
+
url: "https://video.xx.fbcdn.net/...",
|
|
211
|
+
thumbnail_url: "https://scontent.xx.fbcdn.net/...",
|
|
212
|
+
permalink_url: "...",
|
|
213
|
+
length: 15
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
creative_id: "5678",
|
|
217
|
+
object_type: "VIDEO",
|
|
218
|
+
thumbnail_url: "https://scontent.xx.fbcdn.net/...",
|
|
219
|
+
from_post: false,
|
|
220
|
+
error: undefined
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
- **type** is `image`, `video`, `mixed` or `unknown`. `mixed` means the ad
|
|
225
|
+
offers Meta both to choose between, which is what a flexible or dynamic
|
|
226
|
+
creative does, or a carousel with both in it. `unknown` means there is no
|
|
227
|
+
picture or film to be found, as on a text only ad.
|
|
228
|
+
- **carousel** says whether the ad holds more than one card. The cards are
|
|
229
|
+
the entries in `media`, in the order they are shown.
|
|
230
|
+
- **media** has one entry per picture or film, each with a `url` you can
|
|
231
|
+
download. The still that a film shows before it plays is on that film's
|
|
232
|
+
entry as `thumbnail_url`, and does not count as a picture of its own. An
|
|
233
|
+
entry that could not be reached has no `url` and carries an `error` saying
|
|
234
|
+
why instead.
|
|
235
|
+
- **thumbnail_url** is a picture of the ad as it appears. It is there even
|
|
236
|
+
when nothing else is, so it is worth keeping as a fallback: for a film it
|
|
237
|
+
is a still rather than the film itself, which is why it is not in `media`.
|
|
238
|
+
- **from_post** says the ad is boosting a post that was already on your page,
|
|
239
|
+
so the media was read from the post rather than from the ad.
|
|
240
|
+
- **error** is there only when something could not be read, and says what.
|
|
241
|
+
An ad never stops a run over an ad set because of it: you get `unknown`
|
|
242
|
+
and the reason.
|
|
243
|
+
|
|
244
|
+
### Ads that boost a post on your page
|
|
245
|
+
|
|
246
|
+
Much of what is advertised on Facebook and Instagram is a post that already
|
|
247
|
+
exists on a page. Such an ad keeps nothing on the creative but the id of the
|
|
248
|
+
page and of the post:
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
{
|
|
252
|
+
"object_type": "SHARE",
|
|
253
|
+
"object_story_spec": { "page_id": "1067...", "instagram_user_id": "1784..." },
|
|
254
|
+
"effective_object_story_id": "1067..._1334..."
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The picture or the film is on the post, and Meta only shows a post to a token
|
|
259
|
+
that carries that page's own permissions. `get_meta_ad_media` asks for a
|
|
260
|
+
token for the page by itself and reads the post with it, so these ads work
|
|
261
|
+
like any other, as long as the access token in the settings has a say over
|
|
262
|
+
the page. That means:
|
|
263
|
+
|
|
264
|
+
- the token must have the **pages_read_engagement** permission, and
|
|
265
|
+
- the person or system user it belongs to must have a role on that page. In
|
|
266
|
+
Business Manager, add the page to the same business as the ad account and
|
|
267
|
+
give the system user access to it.
|
|
268
|
+
|
|
269
|
+
When that is missing you get `type: "unknown"` and an `error` saying so,
|
|
270
|
+
rather than silence. To check one page on its own:
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
get_meta_page_access_token("106755536029753")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Nothing back means the token has no say over that page. `thumbnail_url` is
|
|
277
|
+
still filled in for these ads, so you have a picture of the ad to look at
|
|
278
|
+
even when the post itself cannot be read.
|
|
279
|
+
|
|
280
|
+
A few things are worth knowing before you download:
|
|
281
|
+
|
|
282
|
+
- **Video addresses are signed and short lived.** Fetch the file as soon as
|
|
283
|
+
you have the address rather than storing the address for later. Meta only
|
|
284
|
+
gives the address out to a token that owns the video: with a read only
|
|
285
|
+
token you may get the video's id and its thumbnail but no `url`, and the
|
|
286
|
+
entry then carries an `error` saying why. `permalink_url` is a stable
|
|
287
|
+
address for watching it, not for downloading it.
|
|
288
|
+
- **Working out the type is cheaper than finding the addresses.** Every film
|
|
289
|
+
costs one extra read to look up. If all you want is image against video,
|
|
290
|
+
use `get_meta_ad_media_type`, or pass the options `{ resolve_urls: false }`.
|
|
291
|
+
- **Pictures are often named by a hash rather than by an address.** The
|
|
292
|
+
address is then held by the ad account's own picture library, which is
|
|
293
|
+
looked up for you, so reading ads of a second ad account works better when
|
|
294
|
+
you pass that account's id: `get_meta_ad_media(ad, { account_id: "..." })`,
|
|
295
|
+
or read the ads with `account_id` among the fields. When the library does
|
|
296
|
+
not hold the picture and the ad boosts a post, the post is read instead.
|
|
297
|
+
- **An ad whose creative shows no media is read again in full.** You may have
|
|
298
|
+
asked Meta for only some of the places media can hide, so rather than
|
|
299
|
+
answer `unknown` too readily it asks for all of them. Handing it an ad you
|
|
300
|
+
read with the creative fields below saves that second read.
|
|
301
|
+
|
|
302
|
+
To go through a whole ad set:
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
const ads = await get_meta_adset_ads(adset_id, {
|
|
306
|
+
fields:
|
|
307
|
+
"id,name,account_id,creative{id,name,object_type,image_url,image_hash," +
|
|
308
|
+
"video_id,thumbnail_url,object_story_spec,asset_feed_spec," +
|
|
309
|
+
"effective_object_story_id}"
|
|
310
|
+
});
|
|
311
|
+
for (const ad of ads) {
|
|
312
|
+
const { type, media } = await get_meta_ad_media(ad);
|
|
313
|
+
console.log(ad.name, type, media.map((m) => m.url));
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Asking for those creative fields is worth doing on a loop like this: given an
|
|
318
|
+
ad that already carries them, `get_meta_ad_media` works from what you have
|
|
319
|
+
instead of reading each ad again. Given only an ad id, it asks for them
|
|
320
|
+
itself.
|
|
321
|
+
|
|
322
|
+
Ads read as a table row, or by `get_meta_ads` without a `fields` of your own,
|
|
323
|
+
carry `creative_object_type`. That is a rough answer on its own: most ads
|
|
324
|
+
that link somewhere are reported as `SHARE` whether the media is a picture or
|
|
325
|
+
a film, so use `get_meta_ad_media` when it matters.
|
|
326
|
+
|
|
167
327
|
## Things to know
|
|
168
328
|
|
|
169
329
|
- **Money is in cents.** Budgets, bids and amounts spent come from Meta as
|