Project Nayuki


How to download private Facebook videos

Introduction

This information has been tested to work at the time of publishing in Nov 2021. But Facebook’s implementation and behavior change continually, so the procedure may become invalid after months or years.

Did you view a video on Facebook and want to save it to a local file? Unfortunately, Facebook never offered a download button for videos (unlike photos). You could try to screen-rip the video by capturing pixels, but that destroys quality and increases file size. Ideally, you want the literal compressed video data that was delivered to your web browser for viewing, which is as clean and efficient as possible, avoiding decoding and re-encoding. Sadly, you can’t use the network inspector (which logs and shows all HTTP requests) to grab a single video file because the data is streamed as an unknown sequence of chunks in an unknown format.

For publicly viewable videos, just use youtube-dl, or visit a third-party web-based downloader service where you can paste in a Facebook URL to get a download link that is proxied through the third-party service.

For private videos (including your own uploads), the situation is tricky and the solution is not obvious. youtube-dl has command-line options to specify a username and password to log into Facebook. I tried this in the past and it sort of worked, but not with two-factor authentication enabled (need to disable it temporarily), and it sometimes triggered security warnings, forcing me to change my account password.

I found a method involving youtube-dl and browser cookies that seems to work well without triggering security problems on Facebook’s side. Please note that this only lets you download private videos that you are already entitled to view (due to the privacy settings of your friend’s post); this is not a hack to download arbitrary private data. Be aware that this procedure is not easy and is oriented towards those who have experience with software development tools and paradigms.

Procedure

Preparation

  1. Grab the URL of the page containing the video that you want to download, as cleanly as possible. If you are browsing a series of posts on the main news feed or on a person’s profile/timeline, then get a permanent link to the post that you’re interested in by clicking on the timestamp text at the top of the post. Ideally, the URL should look like these examples:

    • https://www.facebook.com/jane.example.smith/posts/1234567890
    • https://www.facebook.com/jane.example.smith/videos/1234567890
    • https://www.facebook.com/0123456789/posts/1234567890/
    • https://www.facebook.com/0123456789/videos/1234567890/

    The URL should not look like these (you should strip off the unnecessary parts starting from the question mark):

    • https://www.facebook.com/jane.example.smith/posts/1234567890?__cft__[0]=Ywm9xVMIYfqph6vtEWxBh-fk_bUliDzhCN00uiVZXTylmYuXoPfeIZS-n15nMT4Q-rM13nSC-q4J2Wn4lmfCU-J3gi18rEu_Z_0gzfwyJnnz-gsNISO3_c0vnsZRVhPTcNaRDFt41DTE4NQdPOpM7uom&__tn__=%2CO%2CP-R
    • https://www.facebook.com/0123456789/videos/1234567890/?__tn__=%2CO-R
  2. Close all Facebook tabs in your web browser. Otherwise they will continually make requests in the background and change your cookies.

Cookie extraction (Firefox)

I only have instructions for Mozilla Firefox right now. While the same results can definitely be obtained through Google Chrome, I haven’t personally worked through the steps in order to document them. I have no comment on Apple Safari.

  1. Find the path of your Firefox profile folder by visiting the URL “about:support”. Or you can manually navigate to it using a file explorer, such as “C:\Users\John Q Public\AppData\Roaming\Mozilla\Firefox\Profiles\abcd1234.default” on Windows.

  2. Ensure that you have DB browser for SQLite installed, or you are comfortable with using the sqlite3 command-line tool.

  3. From your Firefox profile folder, open the file cookies.sqlite with the tool mentioned in the previous step.

  4. Run the following SQL query:

    SELECT host, 'TRUE', '/', 'TRUE', expiry, name, value
    FROM moz_cookies
    WHERE host like '%.facebook.com'
  5. Select all the cells of the result table and copy the entirety as plain text. The columns should already be separated by a tab character (U+0009), which you should double-check because it’s mandatory. Example output:

    .facebook.com	TRUE	/	TRUE	1234567890	name0	value0
    .facebook.com	TRUE	/	TRUE	1618033988	name1	value1
    .facebook.com	TRUE	/	TRUE	2345678901	name2	value2

Configuring, downloading, multiplexing

  1. Create a plain text file named cookies.txt (or .tsv if you wish). Ensure that it uses native newlines (according to youtube-dl’s instructions) (LF on Unix/Linux/macOS, CR+LF on Windows). Then paste these two lines followed by a blank line:

    # Netscape HTTP Cookie File
    # This file is generated by youtube-dl.  Do not edit.
  2. Appending to the end of cookies.txt, paste the text obtained from the cookie extraction step, and ensure the file ends with a native newline. The result should look like:

    # Netscape HTTP Cookie File
    # This file is generated by youtube-dl.  Do not edit.
    
    .facebook.com	TRUE	/	TRUE	1234567890	name0	value0
    .facebook.com	TRUE	/	TRUE	1618033988	name1	value1
    .facebook.com	TRUE	/	TRUE	2345678901	name2	value2
  3. Grab the user agent string from the browser that you were using to surf Facebook. This should help reduce the chance of security warnings. In my case, it is “Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0”.

  4. Start building up the command-line string for invoking youtube-dl (don’t run this yet):

    youtube-dl --cookies CookieFile.txt --user-agent UserAgentString PageUrlContainingVideo

    Example:

    youtube-dl --cookies cookies.txt --user-agent "Mozilla/5.0 ... Firefox/94.0" "https://www.facebook.com/jane.example.smith/posts/1234567890"

    The user agent value must be wrapped in quotes or escaped because it contains spaces.

  5. Append the argument -F to our basic command line and then execute it. This will make a request to Facebook and return with a list of all the available video and audio formats. Command-line example:

    youtube-dl --cookies cookies.txt --user-agent "Mozilla/5.0 ... Firefox/94.0" "https://www.facebook.com/jane.example.smith/posts/1234567890" -F

    Output example:

    [facebook] 1234567890: Downloading webpage
    [download] Downloading playlist: 1234567890
    [facebook] playlist 1234567890: Collected 1 video ids (downloading 1 of them)
    [download] Downloading video 1 of 1
    [info] Available formats for 9876543210:
    format code        extension  resolution note
    8367172002096822a  m4a        audio only DASH audio   65k , m4a_dash container, mp4a.40.5 (48000Hz)
    4771281214258710v  mp4        256x144    DASH video   70k , mp4_dash container, avc1.4D401E, video only
    957909568133806v   mp4        426x240    DASH video  149k , mp4_dash container, avc1.4D401E, video only
    339565927899773v   mp4        640x360    DASH video  278k , mp4_dash container, avc1.4D401E, video only
    2138429866841461v  mp4        852x480    DASH video  439k , mp4_dash container, avc1.4D401F, video only
    4360441287725216v  mp4        1280x720   DASH video  862k , mp4_dash container, avc1.4D401F, video only
    6595765927496358v  mp4        1920x1080  DASH video 1869k , mp4_dash container, avc1.4D4028, video only
    sd                 mp4        unknown
    hd                 mp4        unknown    (best)
    [download] Finished downloading playlist: 1234567890

    Note that the random numbers in the format code don’t seem to mean anything. Also, the number after “available formats for” doesn’t correspond with the FBID of the post that you’re trying to download.

  6. Choose a video and audio format, then download it. Given how laborious this procedure is and how cheap computer data transfer/storage is, I strongly advise downloading the largest, highest quality formats to avoid future regret. Append the arguments -f format0,format1 to our basic command line and execute it. Example:

    youtube-dl --cookies cookies.txt --user-agent "Mozilla/5.0 ... Firefox/94.0" "https://www.facebook.com/jane.example.smith/posts/1234567890" -f 6595765927496358v,8367172002096822a

    The run of youtube-dl should produce output like:

    [facebook] 1234567890: Downloading webpage
    [download] Downloading playlist: 1234567890
    [facebook] playlist 1234567890: Collected 1 video ids (downloading 1 of them)
    [download] Downloading video 1 of 1
    [info] 7517720777505659: downloading video in 2 formats
    [download] Destination: Facebook video #7517720777505659-7517720777505659.mp4
    [download] 100% of 7.20MiB in 00:01
    [download] Destination: Facebook video #7517720777505659-7517720777505659.m4a
    [download] 100% of 258.61KiB in 00:00
    [ffmpeg] Correcting container in "Facebook video #7517720777505659-7517720777505659.m4a"
    [download] Finished downloading playlist: 1234567890

    Once again, one of the repeated numbers on the screen (“7517720777505659” in this example) seems random and doesn’t correspond with a format code or the post’s FBID.

  7. For convenience, rename the output video file to “v.mp4” and the audio file to “a.m4a”.

  8. Ensure that you have FFmpeg installed, or have an equivalent utility that you’re comfortable with using.

  9. Using FFmpeg, multiplex the previous video and audio files into a single audio-video output file without recompressing the data. Example command line:

    ffmpeg -i v.mp4 -i a.m4a -vcodec copy -acodec copy out.mp4
  10. You’re essentially done! Pick up the output file out.mp4, then rename and store it as you please.