Upload videos

The YouTubeVideoUploadService lets you upload videos directly to YouTube through the Google Ads API. These videos can then be used to create video assets in various ad types, such as Performance Max campaigns or Demand Gen campaigns .

This service streamlines the workflow of creating video ads by handling the YouTube upload process, ensuring that the videos are correctly associated with your account.

Key concepts

Before you begin, it's important to understand how video uploads are managed and the different states they can go through.

Channel ownership

When you upload a video, you can specify the destination YouTube channel using the channel_id field in the YouTubeVideoUpload resource:

  • Advertiser-owned (brand) channel:Provide the channel_id of a YouTube channel owned by the advertiser. Uploading to a brand channel allows for more control over the video's privacy and visibility.
  • Google-managed channel:If channel_id is omitted, the video is uploaded to a Google-managed YouTube channel associated with the Google Ads account.

Upload states

The lifecycle of a YouTube video upload is tracked by the state field. The YouTubeVideoUploadState enum defines the following states:

State Description
PENDING The video is being uploaded.
UPLOADED The video has been successfully uploaded and is being processed by YouTube.
PROCESSED The video has been successfully processed and is ready for use.
FAILED The upload or processing failed and cannot be completed.
REJECTED The video was rejected due to validation or policy reasons.
UNAVAILABLE The video state is unavailable; it may have been removed from YouTube.

Privacy settings

The video_privacy field controls who can see the uploaded video. The YouTubeVideoPrivacy enum supports:

  • PUBLIC : The video is available to anyone on YouTube. (Only allowed for brand channels).
  • UNLISTED : The video is not searchable but can be viewed by anyone with the link. This is the default and the only option for Google-managed channels.

Upload a video

To upload a video, you must use a multi-part request to the CreateYouTubeVideoUpload method. The request contains both the metadata for the upload and the video file itself.

1. Initiate the upload

Construct a CreateYouTubeVideoUploadRequest specifying the:

  • customer_id : Your Google Ads customer ID.
  • you_tube_video_upload : A YouTubeVideoUpload object with the video_title , video_description , and optionally the channel_id and video_privacy .

If you are using a client library, call the CreateYouTubeVideoUpload method, passing your video file, and the video upload will be handled internally.

Java

This example is not yet available in Java; you can take a look at the other languages.

C#

This example is not yet available in C#; you can take a look at the other languages.

PHP

This example is not yet available in PHP; you can take a look at the other languages.

Python

 yt_service 
 : 
 YouTubeVideoUploadServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "YouTubeVideoUploadService" 
 ) 
 create_upload_request 
 : 
 CreateYouTubeVideoUploadRequest 
 = 
 ( 
 youtube_video_upload_service 
 . 
 CreateYouTubeVideoUploadRequest 
 () 
 ) 
 create_upload_request 
 . 
 customer_id 
 = 
 customer_id 
 create_upload_request 
 . 
 you_tube_video_upload 
 . 
 video_title 
 = 
 "Test Video" 
 create_upload_request 
 . 
 you_tube_video_upload 
 . 
 video_description 
 = 
 ( 
 "Test Video Description" 
 ) 
 create_upload_request 
 . 
 you_tube_video_upload 
 . 
 video_privacy 
 = 
 ( 
 client 
 . 
 enums 
 . 
 YouTubeVideoPrivacyEnum 
 . 
 UNLISTED 
 ) 
 video_upload_resource_name 
 : 
 str 
 with 
 open 
 ( 
 video_file_path 
 , 
 "rb" 
 ) 
 as 
 stream 
 : 
 response 
 : 
 CreateYouTubeVideoUploadResponse 
 = 
 ( 
 yt_service 
 . 
 create_you_tube_video_upload 
 ( 
 stream 
 = 
 stream 
 , 
 request 
 = 
 create_upload_request 
 , 
 retry 
 = 
 None 
 , 
 ) 
 ) 
 video_upload_resource_name 
 = 
 response 
 . 
 resource_name 
 print 
 ( 
 f 
 "Created YouTube video upload: 
 { 
 video_upload_resource_name 
 } 
 " 
 ) 
  

Ruby

This example is not yet available in Ruby; you can take a look at the other languages.

Perl

This example is not yet available in Perl; you can take a look at the other languages.

curl

 # 
 # 
Use  
the  
--i  
curl  
parameter  
to  
capture  
response  
headers  
 in 
  
the  
 $RESPONSE 
 # 
variable. FILE_SIZE=$(wc -c < "${VIDEO_FILE_NAME}" | tr -d '\r') 
 RESPONSE=$(curl -i -f -v -s --request POST \ 
 "https://googleads.googleapis.com/resumable/upload/v${API_VERSION}/customers/${CUSTOMER_ID}/youTubeVideoUploads:create" \ 
 --header "Content-Type: application/json" \ 
 --header "developer-token: ${DEVELOPER_TOKEN}" \ 
 --header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \ 
 --header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \ 
 --header "X-Goog-Upload-Protocol: resumable" \ 
 --header "X-Goog-Upload-Command: start" \ 
 --header "X-Goog-Upload-Header-Content-Length: ${FILE_SIZE}" \ 
 --data @- <<EOF 
 { 
 "customer_id": "${CUSTOMER_ID}", 
 "you_tube_video_upload": { 
 "video_title": "${VIDEO_TITLE}", 
 "video_description": "${VIDEO_DESCRIPTION}", 
 "video_privacy": "UNLISTED" 
 } 
 } 
 EOF 
 ) 
 # 
Extract  
the  
value  
of  
the  
 "x-goog-upload-url" 
  
header  
from  
the  
HTTP  
response. UPLOAD_URL=$(echo "${RESPONSE}" \ 
 | grep -i '^x-goog-upload-url' \ 
 | awk '{print $2}' \ 
 | tr -d '\r') 
 CHUNK_SIZE=$(echo "${RESPONSE}" \ 
 | grep -i '^x-goog-upload-chunk-granularity' \ 
 | awk '{print $2}' \ 
 | tr -d '\r')  
 

If you are using REST, the following section describes how to manage the video upload.

2. Upload the video

When you send a REST request to the CreateYouTubeVideoUpload method, the response contains the URL to be used for uploading the video bytes in the x-goog-upload-url HTTP response header, along with other metadata such as the expected size of each chunk for chunked uploads.

You can also declare the size of the video you are going to upload initially, when starting the process, with the x-goog-upload-header-content-length HTTP request header.

For a full description of the HTTP headers used in the video upload protocol, refer to the following code example:

 # Take the first ${CHUNK_SIZE} bytes of the video file and upload them. 
 head 
  
 - 
 c 
  
 $ 
 { 
 CHUNK_SIZE 
 } 
  
 $ 
 { 
 VIDEO_FILE_NAME 
 } 
  
 | 
  
 curl 
  
 - 
 i 
  
 - 
 v 
  
 - 
 X 
  
 PUT 
  
 "${UPLOAD_URL}" 
  
\ -- 
 header 
  
 "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" 
  
\ -- 
 header 
  
 "X-Goog-Upload-Offset: 0" 
  
\ -- 
 header 
  
 "X-Goog-Upload-Command: upload" 
  
\ -- 
 header 
  
 "Content-Length: ${CHUNK_SIZE}" 
  
\ -- 
 data 
 - 
 binary 
  
 @ 
 - 
 # Query the status of the upload. 
 QUERY_RESPONSE 
 =$ 
 ( 
 curl 
  
 - 
 i 
  
 - 
 s 
  
 - 
 X 
  
 POST 
  
 "${UPLOAD_URL}" 
  
\ -- 
 header 
  
 "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" 
  
\ -- 
 header 
  
 "X-Goog-Upload-Command: query" 
 ) 
 # Extract the value of the "x-goog-upload-size-received" header from the HTTP 
 # response. 
 UPLOADED_BYTES 
 =$ 
 ( 
 echo 
  
 "${QUERY_RESPONSE}" 
  
\  
 | 
  
 grep 
  
 - 
 i 
  
 '^x-goog-upload-size-received' 
  
\  
 | 
  
 awk 
  
 '{print $2}' 
  
\  
 | 
  
 tr 
  
 - 
 d 
  
 ' 
 \r 
 ' 
 ) 
 echo 
  
 "Uploaded ${UPLOADED_BYTES} bytes." 
 REMAINING_BYTES 
 =$ 
 (( 
 FILE_SIZE 
  
 - 
  
 UPLOADED_BYTES 
 )) 
 echo 
  
 "${REMAINING_BYTES} bytes remaining to upload." 
 FINALIZE_RESPONSE 
 =$ 
 ( 
 tail 
  
 - 
 c 
  
 $ 
 { 
 REMAINING_BYTES 
 } 
  
 $ 
 { 
 VIDEO_FILE_NAME 
 } 
  
 | 
  
 curl 
  
 - 
 v 
  
 - 
 X 
  
 PUT 
  
 "${UPLOAD_URL}" 
  
\ -- 
 header 
  
 "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" 
  
\ -- 
 header 
  
 "X-Goog-Upload-Offset: ${UPLOADED_BYTES}" 
  
\ -- 
 header 
  
 "X-Goog-Upload-Command: upload, finalize" 
  
\ -- 
 data 
 - 
 binary 
  
 @ 
 - 
 ) 
 UPLOADED_VIDEO_RESOURCE_NAME 
 =$ 
 ( 
 echo 
  
 $ 
 FINALIZE_RESPONSE 
  
 | 
  
 jq 
  
 - 
 r 
  
 '.resourceName' 
 ) 
  
  

3. Retrieve the video upload state

After you started a video upload, you can retrieve its state by querying the you_tube_video_upload resource with GAQL:

Java

This example is not yet available in Java; you can take a look at the other languages.

C#

This example is not yet available in C#; you can take a look at the other languages.

PHP

This example is not yet available in PHP; you can take a look at the other languages.

Python

 # Retrieve the metadata of the newly uploaded video. 
 query 
 : 
 str 
 = 
 f 
 """ 
 SELECT 
 you_tube_video_upload.resource_name, 
 you_tube_video_upload.video_id, 
 you_tube_video_upload.state 
 FROM you_tube_video_upload 
 WHERE you_tube_video_upload.resource_name = ' 
 { 
 video_upload_resource_name 
 } 
 '""" 
 ga_service 
 : 
 GoogleAdsServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "GoogleAdsService" 
 ) 
 stream 
 : 
 Iterator 
 [ 
 SearchGoogleAdsStreamResponse 
 ] 
 = 
 ga_service 
 . 
 search_stream 
 ( 
 customer_id 
 = 
 customer_id 
 , 
 query 
 = 
 query 
 ) 
 for 
 row 
 in 
 itertools 
 . 
 chain 
 . 
 from_iterable 
 ( 
 batch 
 . 
 results 
 for 
 batch 
 in 
 stream 
 ): 
 video 
 = 
 row 
 . 
 you_tube_video_upload 
 print 
 ( 
 f 
 "Video with ID 
 { 
 row 
 . 
 you_tube_video_upload 
 . 
 video_id 
 } 
 was found in state 
 { 
 row 
 . 
 you_tube_video_upload 
 . 
 state 
 } 
 ." 
 ) 
  

Ruby

This example is not yet available in Ruby; you can take a look at the other languages.

Perl

This example is not yet available in Perl; you can take a look at the other languages.

curl

 curl -i -v -X POST \ 
 "https://qa-prod-googleads.sandbox.googleapis.com/v${API_VERSION}/customers/${CUSTOMER_ID}/googleAds:search" \ 
 --header "Content-Type: application/json" \ 
 --header "Developer-Token: ${DEVELOPER_TOKEN}" \ 
 --header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \ 
 --header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \ 
 --data @- <<EOF 
 { 
 "query": "SELECT you_tube_video_upload.resource_name, you_tube_video_upload.video_id, you_tube_video_upload.state FROM you_tube_video_upload WHERE you_tube_video_upload.resource_name = '$UPLOADED_VIDEO_RESOURCE_NAME'" 
 } 
 EOF  
 

Manage uploads

After a video upload is completed, you can use it as a video asset.

Use the uploaded video

After a video reaches the PROCESSED state, you can find its YouTube video ID in the video_id field of the YouTubeVideoUpload resource.

Use this video_id to create a YoutubeVideoAsset with MutateAssets or link it directly to ad types that support YouTube videos by referencing the video ID.

You can update the metadata of a video uploaded through this API using the UpdateYouTubeVideoUpload method. Only the video_title , video_description , and video_privacy fields can be updated.

Remove uploads

If you need to delete videos uploaded with the Google Ads API, use the RemoveYouTubeVideoUpload method. This will remove the video from both the Google Ads asset library and YouTube.

Design a Mobile Site
View Site in Mobile | Classic
Share by: