25

https://www.youtube.com/get_video_info?video_id={videoId} is throwing

Response status code does not indicate success: 404 (Not Found).

Cfun
  • 8,442
  • 4
  • 30
  • 62
Dhruv Gohil
  • 503
  • 1
  • 5
  • 13
  • Isn't this info in the page metadata? I noticed Youtube is now using standard metadata en OG tags. – Patrick Savalle Aug 18 '21 at 09:04
  • 2
    The solution was to use noembed.com service to get the video informations: Example URL: "https://noembed.com/embed?url=https://www.youtube.com/watch?v=YXN_lNZZAZA" copywrites @Marco https://stackoverflow.com/a/47768013/348589 – Shady Mohamed Sherif Dec 26 '21 at 16:50
  • the noembed.com is the right solution for now (July 2023). All other answers below are not functioning and not retrieve the data from youtube. – Maor Barazany Jul 10 '23 at 13:40

11 Answers11

27

EDIT: I found this can work. I don't why. But it really works.

https://www.youtube.com/get_video_info?video_id=onz2k4zoLjQ&eurl=https%3A%2F%2Fyoutube.googleapis.com%2Fv%2Fonz2k4zoLjQ&html5=1&c=TVHTML5&cver=6.20180913


You can add &html5=1 in the url to fix it.

Zombo
  • 1
  • 62
  • 391
  • 407
EricZhao
  • 746
  • 7
  • 16
  • 21
    Now this way failed too. – EricZhao Jun 18 '21 at 03:58
  • 1
    One thing is different with this new method. Upload and publish date are not available! Am I the only one getting this? – Javid Jun 18 '21 at 17:30
  • 4
    I added `&html5=1&c=TVHTML5&cver=6.20180913` (from the URL in the main post) and it seems like it fixed the problem – avi12 Jun 19 '21 at 13:39
  • 7
    @EricZhao, I think it stopped working with the new solution also. – Akshay katale Jul 22 '21 at 04:21
  • 2
    The new method also stopped working today. @EricZhao you found any solutions for this bro? – Javid Jul 22 '21 at 14:47
  • Still not working for me. Is it working for anyone? – Yash Agarwal Jul 23 '21 at 13:27
  • Hi guys. I just created a new package for C# developers that brings the playable urls. enjoy! https://www.nuget.org/packages/Youtube.VideoInfo/1.0.0 – Ami Vaknin Aug 10 '21 at 22:08
  • 1
    @AmiVaknin I'm guessing there's no publicly available source code I could use to help make myRust library work? – MG lolenstine Aug 11 '21 at 00:08
  • @MGlolenstine it's my code, can I assist? – Ami Vaknin Aug 11 '21 at 11:51
  • @AmiVaknin I have a Rust library that allows us to bypass "certain things" in yt videos, so I need to get direct links. I haven't found any working code for the past few updates, so I'd be interested in how you got it to work. – MG lolenstine Aug 11 '21 at 12:59
  • @MGlolenstine you can create a C# code and use my library, I will soon publish my code – Ami Vaknin Aug 11 '21 at 15:53
  • @AmiVaknin I'll wait for the code to be published :) rewriting the library in C# doesn't help me in the slightest, as there are a few programs relying on my library. – MG lolenstine Aug 11 '21 at 16:07
  • @AmiVaknin "certain things" was referring to age restriction (I wanted to bypass the need for ID or Credit Card info). If your library uses the above way, I got it working. – MG lolenstine Aug 14 '21 at 12:14
  • @MGlolenstine I'm not sure I'm following you... can you elaborate? – Ami Vaknin Aug 15 '21 at 10:42
  • @AmiVaknin There's been tons of [article](https://www.digitalinformationworld.com/2021/06/youtube-gets-stricter-with-age.html)s about it, mostly in EU it would seem. Youtube now requires you to either have a credit card connected to your Google account or send them your ID proving that you're 18+. Youtube-dl stopped working, so did most of other alternatives. That's why I'm looking into making a library that would help me bypass that and let me download the videos. For example [this](https://www.youtube.com/watch?v=7t0SqerlBA0) video doesn't work in incognito (or without confirmation). – MG lolenstine Aug 15 '21 at 11:17
  • @MGlolenstine I think I got you. What my library does is bringing the streaming URLs of videos (without rights...only royalty-free). Download is quite the same but still could be some deltas. I suggest you open fiddler and record all the way of what youtube does. yes, they can do tricks but not magics ;) – Ami Vaknin Aug 15 '21 at 19:52
  • @AmiVaknin yeah, they made tons of changes to the API to prevent people from doing what I am. Right now the only way to get access to those videos is to give them credentials (or use cookies) to an account that has been "activated". – MG lolenstine Aug 15 '21 at 19:59
  • @MGlolenstine I think theres another way, like is used in the JDownloader app. They are not using Official API. – Paulo Costa Aug 16 '21 at 23:06
  • @Paulo A. Costa, I'm looking for the age bypass. I'll take a look tomorrow and see if JDownloader bypasses that. Thanks for pointing it out! – MG lolenstine Aug 16 '21 at 23:16
  • @MGlolenstine They bypass using your login and password. JDownloader is open source (i guess they uses Java language). – Paulo Costa Aug 16 '21 at 23:34
  • @Paulo A. Costa I'm trying to avoid the login info. The problem is that you have to verify your login info using methods not many people want to share. That's what the bypass is for. – MG lolenstine Aug 16 '21 at 23:36
14

I think I've found an alternative to YouTube get_video_info endpoint.

Below is a CURL & PHP (CURL) implementation of the POST request to youtubei/v1/player endpoint with minimum required request headers & parameters.

I've removed many request headers & parameters from the request to stay simple & as anonymous as possible in the same way as when using GET get_video_info endpoint. e.g cookies, user-agent, etc.

Below example may still contain optional request parameters as it was done in emergency.

I found this new API by inspecting the XHR network requests in firefox after setting the user-agent to a television.

firefox-inspect-network-xhr-requests-television-user-agent

Example video link used in CURL request below:

https://www.youtube.com/watch?v=UF8uR6Z6KLc

CURL

 curl 'https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8' -H 'Content-Type: application/json' --data '{  "context": {    "client": {      "hl": "en",      "clientName": "WEB",      "clientVersion": "2.20210721.00.00",      "clientFormFactor": "UNKNOWN_FORM_FACTOR",   "clientScreen": "WATCH",      "mainAppWebInfo": {        "graftUrl": "/watch?v=UF8uR6Z6KLc",           }    },    "user": {      "lockedSafetyMode": false    },    "request": {      "useSsl": true,      "internalExperimentFlags": [],      "consistencyTokenJars": []    }  },  "videoId": "UF8uR6Z6KLc",  "playbackContext": {    "contentPlaybackContext": {        "vis": 0,      "splay": false,      "autoCaptionsDefaultOn": false,      "autonavState": "STATE_NONE",      "html5Preference": "HTML5_PREF_WANTS",      "lactMilliseconds": "-1"    }  },  "racyCheckOk": false,  "contentCheckOk": false}'

PHP (CURL)

function getVideoInfo($video_id){

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, 'https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, '{  "context": {    "client": {      "hl": "en",      "clientName": "WEB",      "clientVersion": "2.20210721.00.00",      "clientFormFactor": "UNKNOWN_FORM_FACTOR",   "clientScreen": "WATCH",      "mainAppWebInfo": {        "graftUrl": "/watch?v='.$video_id.'",           }    },    "user": {      "lockedSafetyMode": false    },    "request": {      "useSsl": true,      "internalExperimentFlags": [],      "consistencyTokenJars": []    }  },  "videoId": "'.$video_id.'",  "playbackContext": {    "contentPlaybackContext": {        "vis": 0,      "splay": false,      "autoCaptionsDefaultOn": false,      "autonavState": "STATE_NONE",      "html5Preference": "HTML5_PREF_WANTS",      "lactMilliseconds": "-1"    }  },  "racyCheckOk": false,  "contentCheckOk": false}');
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');

    $headers = array();
    $headers[] = 'Content-Type: application/json';
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $result = curl_exec($ch);
    if (curl_errno($ch)) {
        echo 'Error:' . curl_error($ch);
    }
    curl_close($ch);
    return $result;

}
Mahad
  • 152
  • 1
  • 3
  • 3
    But where is the key coming from? Could it be, that the key will be blocked in a short term? – Urkman Jul 23 '21 at 14:23
  • The key has been generated from the request they captured, it's probably per-user key. – MG lolenstine Jul 23 '21 at 14:24
  • I found that key and other player data in JavaScript at window.ytcfg.data_ It's set in a script embedded in the HTML, so it should be easy to scrape. – Couchy X Jul 23 '21 at 18:40
  • you're great, it work perfectly with fetch api in js by passing your "postfields" params with JSON.stringify. Thx – bArraxas Dec 14 '22 at 11:18
13

For some reason, Google is trying to make it harder.


Edit Aug 2021:


I just published a new NuGet for C# developers that brings URLs of get_video_info. Enjoy! https://www.nuget.org/packages/Youtube.VideoInfo


The initial value was
https://www.youtube.com/get_video_info?video_id={videoId}&eurl=https://youtube.googleapis.com/v/{videoId}

Then the HTML5 tag was added:
https://www.youtube.com/get_video_info?html5=1&video_id={videoId}&eurl=https://youtube.googleapis.com/v/{videoId}

And now (June 2021) the new solution is:
https://www.youtube.com/get_video_info?video_id={videoId}&eurl=https%3A%2F%2Fyoutube.googleapis.com%2Fv%2Fonz2k4zoLjQ&html5=1&c=TVHTML5&cver=6.20180913

We need to keep our eyes open. looks like someone in google doesn't like the fact that YouTube enables this feature.

Ami Vaknin
  • 194
  • 6
  • Your solution work well. Where did you this update information? – Mankeomorakort Jun 21 '21 at 07:25
  • 3
    Google doesn't like when they don't have total control over everything. Why do you think they discontinued their "don't be evil" motto? It wasn't compatible with their goals anymore. ¬_¬ – Synetech Jun 26 '21 at 02:30
  • Adding `&html5=1&c=TVHTML5&cver=6.20180913` fixed the 404 connection error for me - it looks like the `eurl=` query argument might be optional. – JS Morisset Jul 01 '21 at 16:29
  • 6
    indeed not working. now all these URLs return "410-gone". need to find the new trick ASAP – Ami Vaknin Aug 03 '21 at 16:16
  • 1
    has someone already found a solution? – Ethernets Dec 21 '21 at 11:29
  • https://www.nuget.org/packages/Youtube.VideoInfo – Ami Vaknin Dec 22 '21 at 13:13
  • How to use nuget.org/packages/Youtube.VideoInfo in PHP and does it still work at all in C#? – fabpico Apr 09 '22 at 13:56
  • @fabpico the code is working great in C# and I don't see how youtube can block me now. Regarding PHP: the language is not an issue here, you can build your server in C# - use https://www.nuget.org/packages/Youtube.VideoInfo/ return the links and use it in your PHP code – Ami Vaknin Apr 10 '22 at 15:29
11

Youtube (at time of writing 8 aug 2021) look to have moved the equivalent output into the watch?v= end point. You should find video formats within the ytInitialPlayerResponse (json) variable within the html it returns.

E.g. https://youtube.com/watch?v=SA8ZBJWo73E returns html. Within that html response ytInitialPlayerResponse variable contains a json string. In that string, you can find the video formats under: [streamingData][formats].

I'd love to take all credit but this example commit was where I found the answer.

Simon C
  • 419
  • 3
  • 12
6

UPDATE (July 2021)

I have try this way

POST: https://youtubei.googleapis.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8

with the body :

{
 "context": {
   "client": {
    "hl": "en",
    "clientName": "WEB",
    "clientVersion": "2.20210721.00.00",
    "mainAppWebInfo": {
        "graftUrl": "/watch?v={VIDEO_ID}"
    }
   }
  },
  "videoId": "{VIDEO_ID}"
}

And this work like a charm

toan huynh
  • 73
  • 1
  • 4
4

You can try with this plugin

new YouTubeToHtml5();
<script src="https://cdn.jsdelivr.net/gh/thelevicole/youtube-to-html5-loader@4.0.1/dist/YouTubeToHtml5.js"></script>
<video data-yt2html5="https://www.youtube.com/watch?v=ScMzIvxBSi4" controls></video>
Lavy Ya
  • 41
  • 1
2

This is how I am getting youtube streaming data formats right now. Maybe it can help someone.

var videoInfoUrl =  $"https://www.youtube.com/watch?v={videoId}";
using (var client = new HttpClient())
{
  var videoPageContent = await client.GetStringAsync(videoInfoUrl);

  var regex = new Regex(@"ytInitialPlayerResponse\s*=\s*(\{.+?\})\s*;", RegexOptions.Multiline);
  var match = regex.Match(videoPageContent);

  if (!match.Success)
     return "";

  var json = match.Result("$1");

  var playerResponseJson = JToken.Parse(json);
  var formats = playerResponseJson.SelectToken("streamingData.formats").ToList();
}
Dhruv Gohil
  • 503
  • 1
  • 5
  • 13
  • I have found that nowadays ytInitialPlayerResponse is sometimes available and sometimes not available. Have you noticed the same? – Cyril Gupta Dec 14 '21 at 15:53
0

Try 1060 fix - This issue is yet to be fix in Pytube package. Until it is formally available in Pytube, you can install below one in your system to get downloading work. https://github.com/Zeecka/pytube/tree/fix_1060

For more detail you can refer https://github.com/pytube/pytube/issues/1060

JSH
  • 119
  • 6
0

The best solution I've found so far for Python projects that need the data from the get_video_info API seems to be to use the InnerTube API from the pytube project:

>>> from pytube.innertube import InnerTube
>>> innertube = InnerTube()
>>> video_info = innertube.player("dQw4w9WgXcQ")
>>> video_info.keys()
dict_keys(['responseContext', 'trackingParams', 'adBreakParams', 'playabilityStatus', 'streamingData', 'playbackTracking', 'videoDetails', 'annotations', 'playerConfig', 'storyboards', 'attestation', 'videoQualityPromoSupportedRenderers', 'messages', 'endscreen', 'playerSettingsMenuData'])
>>> video_info["videoDetails"]
{'videoId': 'dQw4w9WgXcQ', 'title': 'Rick Astley - Never Gonna Give You Up (Official Music Video)', 'lengthSeconds': '212', 'keywords': ['rick astley', 'Never Gonna Give You Up', 'nggyu', 'never gonna give you up lyrics', 'rick rolled', 'the boys soundtrack', 'the boys amazon prime', 'Never gonna give you up the boys', 'official', 'Rick Roll', 'music video', 'Rick Astley album', 'rick astley official', 'together forever', 'Whenever You Need Somebody', 'rickrolled', 'WRECK-IT RALPH 2', 'Fortnite song', 'Fortnite event', 'Fortnite dance', 'fortnite never gonna give you up', 'rick astley never gonna give you up', 'rick astley never gonna give you up lyrics'], 'channelId': 'UCuAXFkgsw1L7xaCfnd5JJOw', 'isOwnerViewing': False, 'shortDescription': "Rick Astley's official music video for “Never Gonna Give You Up” \n\nSubscribe to the official Rick Astley YouTube channel: https://RickAstley.lnk.to/YTSubID\n\nFollow Rick Astley:\nFacebook: https://RickAstley.lnk.to/FBFollowID \nTwitter: https://RickAstley.lnk.to/TwitterID \nInstagram: https://RickAstley.lnk.to/InstagramID \nWebsite: https://RickAstley.lnk.to/storeID \nTikTok: https://RickAstley.lnk.to/TikTokID\n\nListen to Rick Astley:\nSpotify: https://RickAstley.lnk.to/SpotifyID \nApple Music: https://RickAstley.lnk.to/AppleMusicID \nAmazon Music: https://RickAstley.lnk.to/AmazonMusicID \nDeezer: https://RickAstley.lnk.to/DeezerID \n\nLyrics:\nWe’re no strangers to love\nYou know the rules and so do I\nA full commitment’s what I’m thinking of\nYou wouldn’t get this from any other guy\n\nI just wanna tell you how I’m feeling\nGotta make you understand\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\nWe’ve known each other for so long\nYour heart’s been aching but you’re too shy to say it\nInside we both know what’s been going on\nWe know the game and we’re gonna play it\n\nAnd if you ask me how I’m feeling\nDon’t tell me you’re too blind to see\n\nNever gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you\n\n#RickAstley #NeverGonnaGiveYouUp #OfficialMusicVideo", 'isCrawlable': True, 'thumbnail': {'thumbnails': [{'url': 'https://i.ytimg.com/vi/dQw4w9WgXcQ/default.jpg', 'width': 120, 'height': 90}, {'url': 'https://i.ytimg.com/vi/dQw4w9WgXcQ/mqdefault.jpg', 'width': 320, 'height': 180}, {'url': 'https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg', 'width': 480, 'height': 360}, {'url': 'https://i.ytimg.com/vi/dQw4w9WgXcQ/sddefault.jpg', 'width': 640, 'height': 480}]}, 'averageRating': 4.893901, 'allowRatings': True, 'viewCount': '1031179782', 'author': 'Rick Astley', 'isPrivate': False, 'isUnpluggedCorpus': False, 'isLiveContent': False}
tonycpsu
  • 407
  • 5
  • 13
0

Dhruv Gohil answer in swift:

private func process(inputString: String) -> [String: Any]?
{
    do {
        let regex = try NSRegularExpression(pattern: "ytInitialPlayerResponse\\s*=\\s*(\\{.+?\\})\\s*;", options: [])
        
        if let match = regex.firstMatch(in: inputString, options: [], range: NSRange(location: 0, length: inputString.utf16.count)),
           let range = Range(match.range(at: 1), in: inputString)
        {
            let jsonString = String(inputString[range])
            let jsonData = jsonString.data(using: .utf8)!
            let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any]
            // json is now a dictionary
            print("\n\n\(jsonString)\n\n")
            return json
        }
    } catch {
        os_trace("pile parsing: got error \(error)", .error)
    }
    return nil
}
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
-4
function getVideo($url)
    {
        parse_str(file_get_contents("https://www.youtube.com/get_video_info?video_id=$url&html5=1"), $data);
        return $finalData = json_decode($data['player_response'], true);
    }
    header('Content-Type: application/json');
    echo json_encode(getVideo('Zrcg7w67Ots'));

I use it like that but sometimes it works and sometimes it doesn't, ie when it returns info sometimes it doesn't Can you fix anything in there, many thanks

C. Peck
  • 3,641
  • 3
  • 19
  • 36