Skip to content
fb

Output

Ten formats, column selection, templates, and the envelope every record carries.

Every command renders through one formatter, so the flags on this page work on all of them.

Formats

auto  table  markdown  list  json  jsonl  csv  tsv  url  raw

auto is the default: a table on a terminal, JSON Lines into a pipe. Which means a command reads well when you type it and pipes cleanly when you do not, without a flag either way.

fb videos nasa -n 2 --fields id,created,plays -o markdown
| id               | created          | plays   |
|------------------|------------------|---------|
| 1380134307388381 | 2026-07-23 16:31 | 457,806 |
| 1376651124309650 | 2026-07-02 15:02 | 600,059 |
fb videos nasa -n 2 --fields id,created,plays -o csv
id,created,plays
1380134307388381,2026-07-23 16:31,"457,806"
1376651124309650,2026-07-02 15:02,"600,059"

-o list is the one to reach for when a record is too wide for a terminal:

fb videos nasa -n 1 -o list
## 1380134307388381
- **created**: 2026-07-23 16:31
- **size**: 3840x2160
- **plays**: 457,806
- **reactions**: 6,023
- **title**: NASA Astronaut Chris Williams: Thinking Like a Scientist
- **url**: https://www.facebook.com/NASA/videos/nasa-astronaut-chris-williams-thinking-like-a-scientist/1380134307388381/

-o url prints one URL per record, which is what makes the shell a pipeline:

fb photos nasa -n 20 -o url | while read u; do fb photo "$u" -o jsonl; done > photos.jsonl
https://www.facebook.com/NASA/videos/nasa-astronaut-chris-williams-thinking-like-a-scientist/1380134307388381/
https://www.facebook.com/NASA/videos/whats-up-july-2026/1376651124309650/

Table columns are not record fields

This is the thing to know before writing a script.

A table shows a chosen handful of columns, formatted for reading: numbers get thousands separators, timestamps get shortened, a count of zero renders as blank and a count that is genuinely unknown renders as n/a. The JSON is the record, whole and unformatted.

fb videos nasa -n 1 -o json
{"tier":0,"surfaces":["s1"],"id":"1380134307388381","url":"…","kind":"video",
 "owner":{},"title":"…","message":{},"post_id":"…","width":3840,"height":2160,
 "created_at":"2026-07-23T16:31:00Z","thumbnail":"…","sd_url":"…","counts":{}}

plays is a column on the videos table and counts is the field in the record. --fields names columns, and a template names record fields. Never assume one list is the other.

--fields

fb videos nasa -n 2 --fields id,created,plays
fb comments "$URL" --fields author,replies,body
fb edges nasa --fields predicate,to,note

Keeps and orders exactly the columns you name, for table, markdown, CSV and TSV. --no-header drops the header row.

fb fields <kind> lists what a record kind has.

--template

A Go text/template applied to each record, one line per record. The names are the JSON field names, lowercase, and nesting works:

fb page 100044561550831 --template '{{.name}} has {{.followers}} followers'
NASA - National Aeronautics and Space Administration has 28000000 followers
fb post "$URL" --template '{{.id}} {{.counts.reactions}}'
1587860636042640 14120

Note the unformatted 28000000, which is the point: a template gives you the record, not the table's rendering of it.

A bad template is caught before any request goes out.

The envelope

Every record carries the same six fields before its own:

{"tier":0,"surfaces":["s1","s3"],
 "sources":["https://www.facebook.com/profile.php?id=100044561550831",
            "https://www.facebook.com/NASA/"],
 "via":{"followers":"s1","likes":"s3","talking_about":"s3"},
 "fetched_at":"2026-07-29T18:02:57.973905Z"}
Field What it says
tier Which tier answered
surfaces Which of the eight surfaces were read
sources The URLs, in order
via Which surface each contested field came from
missed What the read knew it did not get
fetched_at When

via only lists fields where the answer depends on which surface you ask, which is why likes is in it and id is not.

missed is the one to check in a pipeline. A post with 532 comments read from a permalink that ships twenty says so there, and a consumer that ignores it will conclude the post had twenty comments.

Empty is not zero

Tables render a real zero as blank and an unknown as n/a, and those are different facts. An event with nobody going shows a blank; an event whose meta sentence did not carry the numbers shows n/a.

In JSON the same distinction is 0 versus the field being absent. Nothing is defaulted to zero on the way out, because a zero fb invented is indistinguishable from a zero Facebook reported.