Download speed
We hand back links, not files, so how fast a download runs is mostly decided by how you fetch them. The difference between one connection and sixteen is real, and it is not the same on every platform — this page says which links take which treatment, measured rather than assumed.
Which links can be split
A link can be fetched in parallel only if the server behind it answers a ranged request. We asked each one for bytes 1024 to 2047 and wrote down what came back.
| Platform | Ranged requests | What that means |
|---|---|---|
| Yes | Answers 206 with the full size in Content-Range. Split it across as many connections as you like, and resume where you left off. | |
| TikTok | Yes | Answers 206 with the full size. Split it and resume it, but not days later: a video link was signed for about six hours, a photo link for about forty-eight. |
| Yes | Answers 206 with the full size, same as Instagram. The signature held for about thirty-four hours. | |
| Threads | Yes | Answers 206 with the full size. Threads images are served from the same CDN as Instagram photos and were signed for about a hundred hours. |
| VK | No | Answers 400 to a ranged request. One connection from the start, and a dropped connection means starting again. |
| YouTube | No | Not a CDN link at all: the file is streamed from this API's own domain in a single pass, so a Range header is ignored. It is also the shortest-lived link here, about 75 seconds. |
Splitting a download across connections
Where ranges work, this is the single biggest thing you can do. Ask for one slice of the file per connection and join the pieces at the end. Sixteen is a sensible number; past that you are usually queueing rather than downloading.
aria2c -x 16 -s 16 -k 1M \
-o photo.jpg 'https://scontent.cdninstagram.com/…'import concurrent.futures as cf
import httpx
def segment(url, path, parts=16):
"""Fetch one file over several connections, then join the pieces."""
head = httpx.head(url, follow_redirects=True)
if head.headers.get("Accept-Ranges") != "bytes":
# No ranges: one connection is the only option, so take it.
with open(path, "wb") as f, httpx.stream("GET", url, follow_redirects=True) as r:
for chunk in r.iter_bytes():
f.write(chunk)
return
total = int(head.headers["Content-Length"])
span = total // parts
def piece(i):
first = i * span
last = total - 1 if i == parts - 1 else first + span - 1
r = httpx.get(url, headers={"Range": f"bytes={first}-{last}"},
follow_redirects=True, timeout=120)
return i, r.content
with cf.ThreadPoolExecutor(max_workers=parts) as pool:
chunks = dict(pool.map(piece, range(parts)))
with open(path, "wb") as f:
for i in range(parts):
f.write(chunks[i])Where you only get one connection
VK and YouTube have to be taken in one go. Start the download as soon as you have the link rather than putting it in a queue, and never store a YouTube link for later: after about seventy-five seconds it answers 410 and the only fix is another call.
curl -L --fail -o video.mp4 \
'https://api.gapi.dev/dl/dc2cdb0cf9874b9cbdcff5b249b5c054'Knowing the size first
The response carries links, not sizes. For YouTube, /v2/youtube/info lists every quality with its size in bytes, which is one cheap call and lets someone choose before anything is downloaded. Elsewhere a HEAD against the link returns Content-Length, and on the four platforms that accept ranged requests that number is exact.