youtube-apiyoutube-livestreaming-api

Sending Captions to a YouTube Live Stream


I am trying to send captions to a YouTube Live stream (in real time). None of the documentation I've found seems to be accurate.

This page seems closest: https://support.google.com/youtube/answer/6077032?&ref_topic=2853697

But it's still quite wrong. I'm going to walk through what I've done.

  1. Go to YouTube and click on the little grey camera in the upper right that says "Create".
  2. That brings up a popup and and I select "Go Live".
  3. That takes me to studio.youtube.com. I click on the Stream button in the upper left corner.
  4. Enter basic data. Feed the stream URL into OBS. All that works fine.
  5. Set Captions to POST Captions to URL and copy/paste the hidden URL.
  6. Bring everything live then navigate to the Live viewer and watch myself on about a 10-second delay.
  7. Start a program that loops through sending "This is a test" style captions.

They NEVER appear.

My debug statement is this:

Sending to http://upload.youtube.com/closedcaption?cid=abcd-abcd-abcd-abcd-f77s&lang=en-US&seq=364. Body: -->2021-02-10T18:08:46.609 Do not pass go. <--

That is, I'm doing a a POST to the URL in question, Content-Type is set to text/plain. The body is the date/time in Zulu, a newline, my text, and one more newline.

I'm logging this output:

2021/02/10 18:09:09,411 pid<1633> INFO:Post Caption status code: 200
2021/02/10 18:09:09,411 pid<1633> INFO:Post Caption Returned: "2021-02-10T18:09:09.392\n"

That is, YouTube is returning HTTP_OK (200) with a timestamp and nothing else. In other words, it APPEARS to be accepting the caption.

I've made sure I have Show Captions turned on inside the viewer window.

Captions never appear.

I just added the lang argument in case that was the issue -- it doesn't make a difference. I have no idea what I'm doing wrong.

And I can't find any accurate documentation. The page I linked earlier is WRONG. The URL that the website gives as I'm setting up doesn't look anything like what is documented on that page.

You would think, given that YouTube is owned by Google, that a Google search for documentation would actually return some documentation. I actually found the linked page in a StackOverflow answer.

So, questions...

Does anyone know what I might be doing wrong, or have some hints of things I can try?

Does anyone know where I can find up-to-date documentation?

To reiterate:

A. Live streaming (not uploaded video)

B. Captions do NOT appear in the YouTube player

And help or even hints is appreciated.


Here is my latest debug. Language is C++.

Post a caption: This Sending to http://upload.youtube.com/closedcaption?cid=5gb9-x5z8-szbb-ghrr-f77s&seq=50. Body: -->2021-02-20T16:38:16.610 This <-- Post a caption: is Sending to http://upload.youtube.com/closedcaption?cid=5gb9-x5z8-szbb-ghrr-f77s&seq=51. Body: -->2021-02-20T16:38:18.827 is <-- Sending to http://upload.youtube.com/closedcaption?cid=5gb9-x5z8-szbb-ghrr-f77s&seq=52. Body: -->2021-02-20T16:38:20.800

<-- Post a caption: a Sending to http://upload.youtube.com/closedcaption?cid=5gb9-x5z8-szbb-ghrr-f77s&seq=53. Body: -->2021-02-20T16:38:21.047 a <-- Post a caption: test. Sending to http://upload.youtube.com/closedcaption?cid=5gb9-x5z8-szbb-ghrr-f77s&seq=54. Body: -->2021-02-20T16:38:23.264 test. <--

Each message replies with something like this:

2021/02/20 16:37:50,555 pid<538> INFO:Post Caption status code: 200 2021/02/20 16:37:50,555 pid<538> INFO:Post Caption Returned: "2021-02-20T16:37:50.537\n"

I am applying a delta based on the date/time that YouTube sends back, and I am fairly sure that part works.

My results:

-Captions appearing inconsistently. I'm sending with a 2-second delay, and I may or may not see a caption appear.

-When they appear, they stay on the screen very briefly (roughly a 1/2 to 1 second).

-And they appear double:

This is
This is

I'm surprised that. YouTube is generating an http: instead of https:. Switching my URL very slightly changes the behavior, but not enough to matter.


Solution

  • Sending Captions to a YouTube Live Stream

    Yes, that is totally possible! Let me elaborate.

    In order to send closed captions to a live stream, you need to use the contentDetails.closedCaptionsType (contentDetails.enableClosedCaptions is deprecated!) property. You want to send your captions via HTTP POST into the ingestion URL of your live stream - see the documentation:

    closedCaptionsHttpPost: You will send captions, via HTTP POST, to an ingestion URL associated with your live stream.

    On a slight off-topic note, you can get your ingestion URL via contentDetails.closedCaptionsIngestionUrl. It should look like http://upload.youtube.com/closedcaption?cid=xxx-xxx-xxx-xxx, whereas xxx-xxx-xxx-xxx will vary at your end. For further reading, please check out the documentation.


    So.. how do you send closed captions? First off, bear in mind that there are some limitations and requirements. Secondly, decide whether you need to send your CC via a normal HTTP POST request or embedded - see HLS ingestion documentation:

    HLS ingestion supports two options for sending closed captions:

    1. Send closed captions via separate HTTP POST requests. This works for all HLS ingestions.
    2. Embedded 608/708 closed captions work with HLS ingestions that use the H264 video codec but not with ingestions that use the HEVC video codec. See the Live Caption Requirements in the YouTube Help Center for more details.

    What follows is an example of a HTTP POST request to the YouTube API via Python (considering the data that needs to be parsed into, e.g. datetime):

    import requests
    from datetime import datetime
    
    cc = 'This is a test'
    headers = {'content-type': 'text/plain'}
    ingestion_url = 'http://upload.youtube.com/closedcaption?id=xxx-xxx-xxx-xxx=' + str(seq)
    
    #Specify your details
    server = ' region:reg1#cue1' 
    
    #Formatting the time properly
    time = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]
    
    post = time + server + '\n' + cc + '\n'
    
    requests.post(url=ingestion_url, data=post.encode('utf-8'), headers=headers)
    

    Please note:

    1. The server details are optional! You don't need to parse in the region data (see here)
    2. You need to send text/plain post requests, hence {'content-type': 'text/plain'} and .encode('utf-8')
    3. str(seq) is referring to the count string - it must be included in every POST request. Check here.
    4. My example above has been kept really simple. For further reading purposes, I highly suggest looking at this detailed documentation with examples! This YouTube Help article sums up all the needed information (post request, expected return (i.e. 200 and datetime), paramaters, etc.) and provides good examples to test on!

    As you didn't specify the programming language, I went ahead and chose Python. Though you can send the POST request via a normal ingestion url as well. As mentioned couple of times before, the "golden page for your project" shows how to use the pre-given ingestion url (which YouTube will deliver to you) and how to modify it according to said documentation.

    Also note that my explanation above was for their staging server (for simplicity reasons). If you want to test it in the wild, don't forget you need to include parameters like id, ns, sparamas, expire, signature, key and seq.