YouTubeVideoUploadService を使用すると、Google Ads API を介して動画を YouTube に直接アップロードできます。これらの動画は、P-MAX キャンペーンやデマンド ジェネレーション キャンペーンなど、さまざまな広告タイプの動画アセットの作成に使用できます。
このサービスは、YouTube のアップロード プロセスを処理し、動画がアカウントに正しく関連付けられるようにすることで、動画広告の作成ワークフローを効率化します。
主なコンセプト
始める前に、動画のアップロードがどのように管理され、どのような状態になる可能性があるかを理解しておくことが重要です。
エンドツーエンドのワークフロー
動画ファイルをアップロードして広告で配信するには、次の 4 つの手順を順番に行う必要があります。
| ステップ | サービスとメソッド | 概要 |
|---|---|---|
| 1. 動画バイトを開始してアップロードする | YouTubeVideoUploadService の CreateYouTubeVideoUpload |
動画のメタデータとバイナリ ファイルをアップロードして、YouTubeVideoUpload リソース(customers/{customer_id}/youTubeVideoUploads/{video_upload_id})を作成します。 |
| 2. Poll processing state(投票処理の状態) | GoogleAdsService の SearchStream |
state = 'PROCESSED' まで you_tube_video_upload をクエリし、11 文字の YouTube video_id が入力されます。 |
| 3. 再利用可能な動画アセットを作成する | AssetService の MutateAssets |
YoutubeVideoAsset(youtube_video_id = video_id)を作成して、アセット リソース名(customers/{customer_id}/assets/{asset_id})を取得します。 |
| 4. アセットをキャンペーンまたは広告にリンクする | AssetGroupAssetService の MutateAssetGroupAssets、または AdGroupAdService の MutateAdGroupAds |
アセットを P-MAX AssetGroupAsset(field_type = YOUTUBE_VIDEO)またはデマンド ジェネレーション DemandGenVideoResponsiveAdInfo(videos[].asset)にリンクします。 |
チャンネルの所有権
動画をアップロードするときに、YouTubeVideoUpload リソースの channel_id フィールドを使用して、アップロード先の YouTube チャンネルを指定できます。
- 広告主が所有する(ブランド)チャンネル: 広告主が所有する既存の YouTube チャンネルの
channel_idを指定します。これはユーザー認証フローでのみサポートされており、サービス アカウントでは使用できません。 - Google 管理チャンネル:
channel_idが省略されている場合、動画は Google 広告アカウントに関連付けられている Google 管理の YouTube チャンネルにアップロードされます。
アップロードの状態
YouTube 動画のアップロードのライフサイクルは、state フィールドで追跡されます。YouTubeVideoUploadState 列挙型は、次の状態を定義します。
| 州 | 説明 |
|---|---|
PENDING |
動画をアップロードしています。 |
UPLOADED |
動画は正常にアップロードされ、YouTube で処理されています。 |
PROCESSED |
動画が正常に処理され、使用できる状態になりました。 |
FAILED |
アップロードまたは処理に失敗し、完了できません。 |
REJECTED |
検証またはポリシー上の理由により、動画が不承認となりました。 |
UNAVAILABLE |
動画の状態は利用できません。YouTube から削除された可能性があります。 |
プライバシー設定
video_privacy フィールドは、アップロードされた動画を閲覧できるユーザーを制御します。YouTubeVideoPrivacy 列挙型は以下をサポートしています。
PUBLIC: YouTube のすべてのユーザーが視聴できる動画。(ブランド チャンネルでのみ許可されます)。UNLISTED: 動画は検索できませんが、リンクを知っているユーザーなら誰でも視聴できます。これは、Google 管理チャネルのデフォルトかつ唯一のオプションです。
生成コンテンツの開示
v26 以降では、EU AI 規則などの規制に基づき、広告主はアップロードされた動画コンテンツに AI 生成メディアまたは合成メディアが含まれているかどうかを開示できます。
YouTubeVideoUpload の video_content_metadata フィールドに VideoContentMetadata が含まれている。YouTubeVideoUploadGenerativeContentDisclosure 列挙型を使用して、ネストされた generative_content_disclosure フィールドを設定します。
| 値 | 説明 |
|---|---|
NON_GENERATIVE_CONTENT |
広告主様が動画を AI 生成ではないと開示している。 |
GENERATIVE_CONTENT |
広告主様が動画を AI 生成として開示している。 |
動画をアップロード
動画をアップロードするには、CreateYouTubeVideoUpload メソッドへのマルチパート リクエストを使用する必要があります。リクエストには、アップロードのメタデータと動画ファイル自体の両方が含まれます。
1. アップロードを開始する
次のフィールドを使用して CreateYouTubeVideoUploadRequest を作成します。
| フィールド | 要件 | 説明と制約 |
|---|---|---|
customer_id |
必須 | Google 広告のお客様 ID(10 桁、ハイフンなし)。 |
you_tube_video_upload.video_title |
必須(INPUT_ONLY、IMMUTABLE) |
YouTube にアップロードされた動画のタイトル(100 文字以内、< または > を含めることはできません)。 |
you_tube_video_upload.video_description |
省略可(INPUT_ONLY、IMMUTABLE) |
YouTube の動画の説明(半角 5,000 文字まで。< または > を含めることはできません)。 |
you_tube_video_upload.channel_id |
省略可(IMMUTABLE) |
広告主が所有するブランド チャンネルの 24 文字の YouTube チャンネル ID(UC で始まる)。省略すると、Google が管理するチャンネルにアップロードされます。 |
you_tube_video_upload.video_privacy |
省略可(ブランド チャンネルでは変更可能) | YouTubeVideoPrivacy 設定(デフォルトは UNLISTED、広告主が所有するブランド チャンネルの場合は PUBLIC)。 |
you_tube_video_upload.video_content_metadata |
省略可(INPUT_ONLY、IMMUTABLE) |
v26 以降で使用可能: VideoContentMetadata。generative_content_disclosure は YouTubeVideoUploadGenerativeContentDisclosure 値(NON_GENERATIVE_CONTENT または GENERATIVE_CONTENT)に設定します。 |
クライアント ライブラリを使用している場合は、動画ファイルを渡して CreateYouTubeVideoUpload メソッドを呼び出すと、動画のアップロードが内部で処理されます。
Java
String videoUploadResourceName; try (YouTubeVideoUploadServiceClient youTubeVideoUploadServiceClient = googleAdsClient.getLatestVersion().createYouTubeVideoUploadServiceClient()) { YouTubeVideoUpload youTubeVideoUpload = YouTubeVideoUpload.newBuilder() .setVideoTitle("Test Video") .setVideoDescription("Test Video Description") .setVideoPrivacy(YouTubeVideoPrivacy.UNLISTED) .build(); CreateYouTubeVideoUploadRequest createUploadRequest = CreateYouTubeVideoUploadRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .setYouTubeVideoUpload(youTubeVideoUpload) .build(); CreateYouTubeVideoUploadResponse response = youTubeVideoUploadServiceClient.createYouTubeVideoUpload( createUploadRequest, () -> new FileInputStream(videoFile), null); videoUploadResourceName = response.getResourceName(); System.out.printf("Created YouTube video upload: %s%n", videoUploadResourceName); }
C#
YouTubeVideoUploadServiceClient ytService = client.GetService( Services.V26.YouTubeVideoUploadService); CreateYouTubeVideoUploadRequest createUploadRequest = new CreateYouTubeVideoUploadRequest() { CustomerId = customerId.ToString(), YouTubeVideoUpload = new YouTubeVideoUpload() { VideoTitle = "Test Video", VideoDescription = "Test Video Description", VideoPrivacy = YouTubeVideoPrivacy.Unlisted } }; string videoUploadResourceName; using (FileStream stream = File.OpenRead(videoFilePath)) { ResumableUploadSession<CreateYouTubeVideoUploadRequest, CreateYouTubeVideoUploadResponse> session = ytService.CreateYouTubeVideoUpload(); CreateYouTubeVideoUploadResponse response = session.BeginUploadAsync(createUploadRequest, stream).Result; videoUploadResourceName = response.ResourceName; Console.WriteLine($"Created YouTube video upload: {videoUploadResourceName}"); }
PHP
$youTubeVideoUploadServiceClient = $googleAdsClient->getYouTubeVideoUploadServiceClient(); $youTubeVideoUpload = new YouTubeVideoUpload([ 'video_title' => 'Test Video', 'video_description' => 'Test Video Description', 'video_privacy' => YouTubeVideoPrivacy::UNLISTED ]); $createYouTubeVideoUploadRequest = CreateYouTubeVideoUploadRequest::build( $customerId, $youTubeVideoUpload ); /** @var ResumableUpload $resumableUpload */ $resumableUpload = $youTubeVideoUploadServiceClient->createYouTubeVideoUpload( $createYouTubeVideoUploadRequest ); $stream = Utils::streamFor(fopen($videoFilePath, 'rb')); /** @var CreateYouTubeVideoUploadResponse $response */ $response = $resumableUpload->startUpload($stream); $videoUploadResourceName = $response->getResourceName(); printf("Created YouTube video upload: '%s'%s", $videoUploadResourceName, PHP_EOL);
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
video_upload = client.resource.you_tube_video_upload do |v| v.video_title = "Test Video" v.video_description = "Test Video Description" v.video_privacy = :UNLISTED end upload = client.service.you_tube_video_upload.create_you_tube_video_upload( customer_id: customer_id, you_tube_video_upload: video_upload, ) video_upload_resource_name = nil File.open(video_file_path, "rb") do |stream| response = upload.start( stream: stream, content_type: "application/octet-stream", ) video_upload_resource_name = response.resource_name puts "Created YouTube video upload: #{video_upload_resource_name}" end
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 "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')
REST を使用している場合は、次のセクションで動画のアップロードを管理する方法について説明します。
2. 動画をアップロードする
REST でアップロードする場合、CreateYouTubeVideoUpload は 2 ステップの再開可能なアップロード プロトコルを使用します。
- アップロード セッションを開始する:
x-goog-upload-command: start(および必要に応じてファイルサイズを宣言するx-goog-upload-header-content-length)を指定して、CreateYouTubeVideoUploadアップロード エンドポイント(/upload/v26/customers/{customer_id}/youTubeVideoUploads:create)に最初のPOSTリクエストを送信します。レスポンスは、想定されるチャンクサイズなどのメタデータとともに、x-goog-upload-urlHTTP レスポンス ヘッダーにアップロード セッション URL を返します。 - 動画バイトをストリーミングしてファイナライズする:
x-goog-upload-command: upload, finalizeを使用して、バイナリ動画ペイロードをx-goog-upload-urlエンドポイントに送信します。アップロードが完了すると、レスポンスは作成されたresource_name(customers/{customer_id}/youTubeVideoUploads/{video_upload_id})を返します。
動画アップロード プロトコルで使用される HTTP ヘッダーの詳細については、次のコード例をご覧ください。
# 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. 動画のアップロード ステータスを取得する
動画のアップロードを開始したら、you_tube_video_upload リソースの選択可能なフィールド(resource_name、video_upload_id、channel_id、video_id、state、video_privacy)を GAQL でクエリして、state = 'PROCESSED' になるまで処理状態をポーリングします(INPUT_ONLY フィールドは GAQL で選択できません)。
Java
// Retrieve the metadata of the newly uploaded video. String query = String.format( "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 = '%s'", videoUploadResourceName); try (GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) { SearchGoogleAdsStreamRequest request = SearchGoogleAdsStreamRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .setQuery(query) .build(); ServerStream<SearchGoogleAdsStreamResponse> stream = googleAdsServiceClient.searchStreamCallable().call(request); for (SearchGoogleAdsStreamResponse response : stream) { for (GoogleAdsRow googleAdsRow : response.getResultsList()) { YouTubeVideoUpload video = googleAdsRow.getYouTubeVideoUpload(); System.out.printf( "Video with ID %s was found in state %s.%n", video.getVideoId(), video.getState()); } } }
C#
// Retrieve the metadata of the newly uploaded video. string 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 = '{videoUploadResourceName}'"; GoogleAdsServiceClient gaService = client.GetService( Services.V26.GoogleAdsService); gaService.SearchStream(customerId.ToString(), query, delegate (SearchGoogleAdsStreamResponse resp) { foreach (GoogleAdsRow row in resp.Results) { Console.WriteLine( $"Video with ID {row.YouTubeVideoUpload.VideoId} was found in " + $"state {row.YouTubeVideoUpload.State}."); } } );
PHP
// Retrieve the metadata of the newly uploaded video. $query = sprintf( "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 = '%s'", $videoUploadResourceName ); $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient(); $stream = $googleAdsServiceClient->searchStream( SearchGoogleAdsStreamRequest::build($customerId, $query) ); foreach ($stream->iterateAllElements() as $googleAdsRow) { /** @var GoogleAdsRow $googleAdsRow */ printf( "Video with ID '%s' was found in state '%s'.%s", $googleAdsRow->getYouTubeVideoUpload()->getVideoId(), YouTubeVideoUploadState::name($googleAdsRow->getYouTubeVideoUpload()->getState()), PHP_EOL ); }
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
# Retrieve the metadata of the newly uploaded video. query = <<~EOQ 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}' EOQ responses = client.service.google_ads.search_stream( customer_id: customer_id, query: query, ) responses.each do |batch| batch.results.each do |row| puts "Video with ID #{row.you_tube_video_upload.video_id} was found in " \ "state #{row.you_tube_video_upload.state}." end end
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
アップロードを管理
動画のアップロードが完了すると、動画アセットとして使用できるようになります。
アップロードした動画を使用する
動画が PROCESSED 状態になると、YouTubeVideoUpload リソースの video_id フィールドに 11 文字の YouTube 動画 ID が表示されます。
この video_id を使用して MutateAssets で YoutubeVideoAsset を作成し、結果として得られたアセット リソース名(customers/{customer_id}/assets/{asset_id})をキャンペーンまたは広告にリンクします。
youtube_video_idをAssetService.MutateAssetsに渡して、YoutubeVideoAssetを作成します。POST https://googleads.googleapis.com/v26/customers/{customer_id}/assets:mutate { "operations": [ { "create": { "name": "Product Launch Video", "youtubeVideoAsset": { "youtubeVideoId": "dQw4w9WgXcQ" } } } ] }AssetをAssetGroupまたはAdGroupAdにリンクする:P-MAX:
field_typeをYOUTUBE_VIDEOに設定したAssetGroupAssetService.MutateAssetGroupAssetsを使用してAssetGroupAssetを作成します。POST https://googleads.googleapis.com/v26/customers/{customer_id}/assetGroupAssets:mutate { "operations": [ { "create": { "assetGroup": "customers/{customer_id}/assetGroups/{asset_group_id}", "asset": "customers/{customer_id}/assets/{asset_id}", "fieldType": "YOUTUBE_VIDEO" } } ] }デマンド ジェネレーション:
AdGroupAdService.MutateAdGroupAdsを呼び出すときに、DemandGenVideoResponsiveAdInfoオブジェクトのvideosリストでcustomers/{customer_id}/assets/{asset_id}を参照します。POST https://googleads.googleapis.com/v26/customers/{customer_id}/adGroupAds:mutate { "operations": [ { "create": { "adGroup": "customers/{customer_id}/adGroups/{ad_group_id}", "status": "PAUSED", "ad": { "name": "Demand Gen Video Ad", "finalUrls": ["https://www.example.com"], "demandGenVideoResponsiveAd": { "videos": [ { "asset": "customers/{customer_id}/assets/{asset_id}" } ], "logoImages": [ { "asset": "customers/{customer_id}/assets/{logo_asset_id}" } ], "headlines": [ { "text": "Example Headline" } ], "longHeadlines": [ { "text": "Example Long Headline" } ], "descriptions": [ { "text": "Example Description" } ], "businessName": { "text": "Example Business" } } } } } ] }
GoogleAdsService.SearchStreamを使用して既存のYOUTUBE_VIDEOアセットをクエリする:SELECT asset.id, asset.resource_name, asset.name, asset.type, asset.youtube_video_asset.youtube_video_id, asset.youtube_video_asset.youtube_video_title FROM asset WHERE asset.type = 'YOUTUBE_VIDEO' AND asset.youtube_video_asset.youtube_video_id = '{video_id}'
メタデータを更新
この API を介してアップロードされた動画のプライバシー設定は、update_mask を "video_privacy" に設定した UpdateYouTubeVideoUpload メソッドを使用して更新できます。作成後に更新できるのは video_privacy フィールド(広告主所有のブランド チャンネルにアップロードされた動画の場合は PUBLIC または UNLISTED)のみです。video_title、video_description、channel_id、video_content_metadata は変更できません。
アップロードを削除する
Google Ads API でアップロードした動画を削除する必要がある場合は、RemoveYouTubeVideoUpload メソッドの resource_names フィールドに customers/{customer_id}/youTubeVideoUploads/{video_upload_id} リソース名を渡します。これにより、動画は Google 広告のアセット ライブラリと YouTube の両方から削除されます。