Repository: yt-dlp/yt-dlp
Issue category: Bug Report

Issue:
[youtube] Age-restricted videos now always require sign-in
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

_No response_

### Provide a description that is worded well enough to be understood

I'm unable to download any age restricted videos without signing in. Wasn't a problem till a week ago.
I'm on the latest nightly and it fails with or without the AGP plugin.



### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
C:\Users\Casey>yt-dlp https://www.youtube.com/watch?v=7Do70nztRNE -vU
[debug] Command-line config: ['https://www.youtube.com/watch?v=7Do70nztRNE', '-vU']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds [679c68240] (pip)
[debug] Python 3.11.2 (CPython AMD64 64bit) - Windows-10-10.0.19044-SP0 (OpenSSL 1.1.1s  1 Nov 2022)
[debug] exe versions: ffmpeg 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev (setts), ffprobe 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2022.12.07, curl_cffi-0.5.10, mutagen-1.47.0, requests-2.32.3, sqlite3-3.39.4, urllib3-1.26.18, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Extractor Plugins: AGB (YoutubeIE)
[debug] Plugin directories: ['C:\\Users\\Casey\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\yt_dlp_plugins']
[debug] Loaded 1838 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds)
[youtube+AGB] Extracting URL: https://www.youtube.com/watch?v=7Do70nztRNE
[youtube+AGB] 7Do70nztRNE: Downloading webpage
[youtube+AGB] 7Do70nztRNE: Downloading ios player API JSON
[youtube+AGB] 7Do70nztRNE: This video is age-restricted; some formats may be missing without authentication. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[youtube+AGB] 7Do70nztRNE: Downloading tv embedded player API JSON
[youtube+AGB] 7Do70nztRNE: Downloading mweb player API JSON
[youtube+AGB] 7Do70nztRNE: Downloading Zerody API JSON
WARNING: [youtube+AGB] Unable to download JSON metadata: HTTP Error 502: Bad Gateway
ERROR: [youtube+AGB] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 741, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\youtube.py", line 4468, in _real_extract
    self.raise_no_formats(reason, expected=True)
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 1275, in raise_no_formats
    raise ExtractorError(msg, expected=expected, video_id=video_id)
```



Hints:
please provide a log without the plugin. run `set YTDLP_NO_PLUGINS=1` and then your download command again
Log without the AGP plugin

```
C:\Users\Casey>yt-dlp https://www.youtube.com/watch?v=7Do70nztRNE -vU
[debug] Command-line config: ['https://www.youtube.com/watch?v=7Do70nztRNE', '-vU']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds [679c68240] (pip)
[debug] Python 3.11.2 (CPython AMD64 64bit) - Windows-10-10.0.19044-SP0 (OpenSSL 1.1.1s  1 Nov 2022)
[debug] exe versions: ffmpeg 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev (setts), ffprobe 2023-07-06-git-f00222e81f-essentials_build-www.gyan.dev
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2022.12.07, curl_cffi-0.5.10, mutagen-1.47.0, requests-2.32.3, sqlite3-3.39.4, urllib3-1.26.18, websockets-13.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets, curl_cffi
[debug] Loaded 1838 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest
Latest version: nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds
yt-dlp is up to date (nightly@2024.10.19.232833 from yt-dlp/yt-dlp-nightly-builds)
[youtube] Extracting URL: https://www.youtube.com/watch?v=7Do70nztRNE
[youtube] 7Do70nztRNE: Downloading webpage
[youtube] 7Do70nztRNE: Downloading ios player API JSON
[youtube] 7Do70nztRNE: This video is age-restricted; some formats may be missing without authentication. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies
[youtube] 7Do70nztRNE: Downloading tv embedded player API JSON
[youtube] 7Do70nztRNE: Downloading mweb player API JSON
ERROR: [youtube] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 741, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\youtube.py", line 4468, in _real_extract
    self.raise_no_formats(reason, expected=True)
  File "C:\Users\Casey\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 1275, in raise_no_formats
    raise ExtractorError(msg, expected=expected, video_id=video_id)
```

> ERROR: [youtube] 7Do70nztRNE: Sign in to confirm your age. This video may be inappropriate for some users.

The `tv_embedded` client that yt-dlp was using to work around the age-restriction now requires sign-in for every video, so it is no longer useful for this purpose.

The [linked pull request that will close this issue](https://github.com/yt-dlp/yt-dlp/pull/11297) merely removes the broken age-gate workaround and now-misleading warning message.

**There will likely not be a solution to this besides authenticating with cookies or oauth.**
(Obligatory mention of the [**risk you would be taking if you use cookies or oauth**](https://github.com/yt-dlp/yt-dlp/issues/10085))

---

> [youtube+AGB] 7Do70nztRNE: Downloading Zerody API JSON
> WARNING: [youtube+AGB] Unable to download JSON metadata: HTTP Error 502: Bad Gateway

As for the plugin error, that is out-of-scope for this issue tracker. It looks like an issue with the AGB API (the server, not the plugin code). There's likely nothing that the maintainer of the yt-dlp plugin can do about that either.
This is disappointing. I've already had an account blocked by Google when using oauth so downloading without signing in was the only real option for me.


So is there any workaround that anyone knows? 
@eytay Your options are:
- Provide cookies to yt-dlp at the risk of your account getting blocked if you download an excessive amount
- Try the [YTAgeGateBypass](https://github.com/pukkandan/yt-dlp-YTAgeGateBypass) plugin (as you already did). This relies on a public account proxy and might not work.

I am surprised the bypass yt-dlp used worked for as long as it did.
It can't read my cookies, no matter from browser or the cookies.sqlite.
```
[ytdl_hook] ERROR: 'utf-8' codec can't decode byte 0x80 in position 16: invalid start byte
[ytdl_hook] ERROR: 'utf-8' codec can't decode byte 0x80 in position 16: invalid start byte
[ytdl_hook] youtube-dl failed: unexpected error occurred
Failed to recognize file format.
```
@laichiaheng `--cookies` requires a netscape cookie file. NOT the sqlite file your browser uses. If you want yt-dlp to read the cookies directly from your browser use `--cookies-from-browser`. If you need further help please open a new issue with a complete verbose log.
> @laichiaheng `--cookies` requires a netscape cookie file. NOT the sqlite file your browser uses. If you want yt-dlp to read the cookies directly from your browser use `--cookies-from-browser`. If you need further help please open a new issue with a complete verbose log.

I did, but it showed me the same error.

Nevermind, it seems to be fixed with the latest update, I guess, I can play the video with cookies from browser now.
Workaround for age-restricted and similar issues. This uses a personal throw-away google account, and optionally uses tor.

#### start a browser with a temp/throway profile (optionally with tor).
`torsocks chromium  --temp-profile`

#### add an extension to export cookies.txt - "Get cookies.txt LOCALLY".
chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc


#### pin that extension to the taskbar.

#### create a google account using the temp-profile browser instance.

#### make a note of login credentials, in case you need to access the account later.

#### go to youtube, this sets YT cookies in the browser.

#### find an age-restricted video, and verify that you want to see it.

#### use the `Get cookies.txt LOCALLY` extension to "Export All Cookies".

#### (optional) re-name the saved cookies file to something more meaningful:
`mv -vi ~/Downloads/cookies.txt ~/Downloads/cookies-throwaway.txt`

#### (optional) check that only a minimal set of domains is stored in that cookie file:
```
awk '{print $1}' ~/Downloads/cookies-throwaway.txt | sort -u

#
accounts.google.com
.chromewebstore.google.com
chromewebstore.google.com
.google.com
.google.co.nz
ogs.google.com
www.google.com
.youtube.com
```
#### profit:
`torsocks yt-dlp --cookies ~/Downloads/cookies-throwaway.txt ...`

#### (optional) save the login credentials where they can be found when needed. DO NOT ADD THIS TO THE COOKIES.TXT FILE.
```
cat ~/Downloads/cookies-throwaway-login.txt  
name: xxxxxx
login: xxxxxx
pass:	xxxxxx
```

@atom-smasher

Thank you for this. But is creating Google Account without any personal information (e.g SMS verification) a challenge in itself?
> Thank you for this. But is creating Google Account without any personal information (e.g SMS verification) a challenge in itself?

It can be, but as I was going through step-by-step to document the process, it did not ask for any SMS verification.

I don't remember… It may have asked for something like a phone-number or backup email address, for account recovery purposes, but if it did, I was able to “skip” past them.
@atom-smasher How exactly you make your throwaway accounts? What browser/VPN server or real IP country/3rd party email if any for recovery/ask for new gmail as main or just use 3rd party as main/believable name/bd/etc were you using? I think probably all of this and more affects if you get forced phone verification or not. I had an old burner account I made with VPN and Edge but it got blocked trying it now.

Patch:
diff --git a/yt_dlp/extractor/youtube.py b/yt_dlp/extractor/youtube.py
index fd9c7107c7f7..b12a22d852ab 100644
--- a/yt_dlp/extractor/youtube.py
+++ b/yt_dlp/extractor/youtube.py
@@ -1495,7 +1495,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
         },
         # Age-gate videos. See https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-888837000
         {
-            'note': 'Embed allowed age-gate video',
+            'note': 'Embed allowed age-gate video; works with web_embedded',
             'url': 'https://youtube.com/watch?v=HtVdAasjOgU',
             'info_dict': {
                 'id': 'HtVdAasjOgU',
@@ -1525,7 +1525,6 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
                 'heatmap': 'count:100',
                 'timestamp': 1401991663,
             },
-            'skip': 'Age-restricted; requires authentication',
         },
         {
             'note': 'Age-gate video with embed allowed in public site',
@@ -3983,10 +3982,20 @@ def append_client(*client_names):
                 else:
                     prs.append(pr)
 
+            # web_embedded can work around age-gate and age-verification for some embeddable videos
+            if self._is_agegated(pr) and variant != 'web_embedded':
+                append_client(f'web_embedded.{base_client}')
+            # Unauthenticated users will only get web_embedded client formats if age-gated
+            if self._is_agegated(pr) and not self.is_authenticated:
+                self.to_screen(
+                    f'{video_id}: This video is age-restricted; some formats may be missing '
+                    f'without authentication. {self._login_hint()}', only_once=True)
+
             ''' This code is pointless while web_creator is in _DEFAULT_AUTHED_CLIENTS
             # EU countries require age-verification for accounts to access age-restricted videos
             # If account is not age-verified, _is_agegated() will be truthy for non-embedded clients
-            if self.is_authenticated and self._is_agegated(pr):
+            embedding_is_disabled = variant == 'web_embedded' and self._is_unplayable(pr)
+            if self.is_authenticated and (self._is_agegated(pr) or embedding_is_disabled):
                 self.to_screen(
                     f'{video_id}: This video is age-restricted and YouTube is requiring '
                     'account age-verification; some formats may be missing', only_once=True)


Test patch: