Com o YouTubeVideoUploadService,
você pode enviar vídeos diretamente para o YouTube usando a API Google Ads. Esses
vídeos podem ser usados para criar recursos de vídeo em vários tipos de anúncios, como
campanhas Performance Max ou
campanhas Geração de Demanda.
Esse serviço simplifica o fluxo de trabalho de criação de anúncios em vídeo ao lidar com o processo de upload do YouTube, garantindo que os vídeos sejam associados corretamente à sua conta.
Principais conceitos
Antes de começar, é importante entender como os envios de vídeos são gerenciados e os diferentes estados pelos quais eles podem passar.
Fluxo de trabalho completo
O upload de um arquivo de vídeo e a veiculação dele em um anúncio exigem quatro etapas sequenciais:
| Etapa | Serviço e método | Resumo |
|---|---|---|
| 1. Iniciar e fazer upload de bytes de vídeo | CreateYouTubeVideoUpload em YouTubeVideoUploadService |
Faça upload dos metadados do vídeo e do arquivo binário para criar um recurso YouTubeVideoUpload (customers/{customer_id}/youTubeVideoUploads/{video_upload_id}). |
| 2. Estado de processamento da enquete | SearchStream em GoogleAdsService |
Consulte you_tube_video_upload até state = 'PROCESSED' e o video_id de 11 caracteres do YouTube será preenchido. |
| 3. Criar um recurso de vídeo reutilizável | MutateAssets em AssetService |
Crie um YoutubeVideoAsset (youtube_video_id = video_id) para receber um nome de recurso de recurso (customers/{customer_id}/assets/{asset_id}). |
| 4. Vincular o recurso a campanhas ou anúncios | MutateAssetGroupAssets no AssetGroupAssetService ou MutateAdGroupAds no AdGroupAdService |
Vincule o recurso a uma campanha Performance Max AssetGroupAsset (field_type = YOUTUBE_VIDEO) ou Geração de Demanda DemandGenVideoResponsiveAdInfo (videos[].asset). |
Propriedade do canal
Ao enviar um vídeo, você pode especificar o canal de destino do YouTube usando
o campo channel_id no recurso
YouTubeVideoUpload:
- Canal de propriedade do anunciante (marca):forneça o
channel_idde um canal do YouTube que pertence ao anunciante. Isso só é compatível com o fluxo de autenticação do usuário. Não é possível usar contas de serviço. - Canal gerenciado pelo Google:se
channel_idfor omitido, o vídeo será enviado para um canal do YouTube gerenciado pelo Google associado à conta do Google Ads.
Estados de upload
O ciclo de vida do envio de um vídeo do YouTube é monitorado pelo campo state.
O tipo enumerado YouTubeVideoUploadState
define os seguintes estados:
| Estado | Descrição |
|---|---|
PENDING |
O vídeo está sendo enviado. |
UPLOADED |
O vídeo foi enviado e está sendo processado pelo YouTube. |
PROCESSED |
O vídeo foi processado e está pronto para uso. |
FAILED |
O upload ou o processamento falhou e não pode ser concluído. |
REJECTED |
O vídeo foi rejeitado por motivos de validação ou política. |
UNAVAILABLE |
O estado do vídeo está indisponível. Ele pode ter sido removido do YouTube. |
Configurações de privacidade
O campo video_privacy controla quem pode ver o vídeo enviado. O tipo enumerado
YouTubeVideoPrivacy
aceita:
PUBLIC: o vídeo está disponível para qualquer pessoa no YouTube. (Permitido apenas para canais de marca).UNLISTED: o vídeo não aparece em pesquisas, mas pode ser assistido por qualquer pessoa que tenha o link. Essa é a única opção padrão para canais gerenciados pelo Google.
Requisitos de título e descrição
Ao criar um upload de vídeo, é possível especificar metadados usando os campos video_title
e video_description no recurso YouTubeVideoUpload:
video_title: obrigatório. O título não pode exceder 100 caracteres nem conter caracteres inválidos (colchetes angulares<ou>). Ele só pode ser definido ao criar o upload do vídeo e é imutável após a criação.video_description: opcional. A descrição não pode exceder 5.000 caracteres e não pode conter caracteres inválidos (colchetes angulares<ou>). Ela só pode ser definida ao criar o upload do vídeo e é imutável após a criação.
Os dois campos são imutáveis após a criação. A inclusão de video_title ou
video_description na máscara de atualização de uma
solicitação UpdateYouTubeVideoUpload falha com um
erro FieldError.IMMUTABLE_FIELD.
Para mais informações sobre a formatação de títulos e descrições do YouTube e caracteres inválidos, consulte a Central de Ajuda do YouTube.
Declaração de conteúdo gerado com IA
A partir da v26, de acordo com regulamentações como a Lei de IA da UE, os anunciantes podem declarar se o conteúdo de vídeo enviado tem mídia sintética ou gerada com IA.
O campo video_content_metadata em YouTubeVideoUpload contém
VideoContentMetadata. Defina o campo
generative_content_disclosure aninhado usando o
tipo enumerado
YouTubeVideoUploadGenerativeContentDisclosure:
| Valor | Descrição |
|---|---|
NON_GENERATIVE_CONTENT |
O anunciante declarou que o vídeo não foi gerado com IA. |
GENERATIVE_CONTENT |
O anunciante declarou que o vídeo foi gerado com IA. |
Enviar um vídeo
Para fazer upload de um vídeo, use uma solicitação de várias partes para o método CreateYouTubeVideoUpload. A solicitação contém os metadados do
upload e o próprio arquivo de vídeo.
1. Iniciar o upload
Crie um CreateYouTubeVideoUploadRequest com os seguintes campos:
| Campo | Requisito | Descrição e restrições |
|---|---|---|
customer_id |
Obrigatório | O ID de cliente do Google Ads com 10 dígitos (sem hífens). |
you_tube_video_upload.video_title |
Obrigatório (INPUT_ONLY, IMMUTABLE) |
Título do vídeo enviado para o YouTube (até 100 caracteres, não pode conter < ou >). |
you_tube_video_upload.video_description |
Opcional (INPUT_ONLY, IMMUTABLE) |
Descrição do vídeo no YouTube (até 5.000 caracteres,sem < ou >). |
you_tube_video_upload.channel_id |
Opcional (IMMUTABLE) |
ID de 24 caracteres do canal de destino do YouTube (começando com UC) para um canal de marca de propriedade do anunciante. Se omitido, o upload será feito em um canal gerenciado pelo Google. |
you_tube_video_upload.video_privacy |
Opcional (mutável em canais de marca) | Configuração YouTubeVideoPrivacy (UNLISTED por padrão ou PUBLIC para canais de marca de propriedade do anunciante). |
you_tube_video_upload.video_content_metadata |
Opcional (INPUT_ONLY, IMMUTABLE) |
Disponível a partir da v26: VideoContentMetadata com generative_content_disclosure definido como um valor YouTubeVideoUploadGenerativeContentDisclosure (NON_GENERATIVE_CONTENT ou GENERATIVE_CONTENT). |
Se você estiver usando uma biblioteca de cliente, chame o método CreateYouTubeVideoUpload, transmitindo o arquivo de vídeo, e o upload do vídeo será processado internamente.
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')
Se você estiver usando REST, a seção a seguir descreve como gerenciar o envio de vídeos.
2. Envie o vídeo
Ao fazer upload com REST, o CreateYouTubeVideoUpload usa um protocolo de upload retomável em duas etapas:
- Inicie a sessão de upload:envie uma solicitação
POSTinicial para o endpoint de upload doCreateYouTubeVideoUpload(/upload/v26/customers/{customer_id}/youTubeVideoUploads:create) comx-goog-upload-command: start(e, opcionalmente,x-goog-upload-header-content-lengthpara declarar o tamanho do arquivo). A resposta retorna o URL da sessão de upload no cabeçalho de resposta HTTPx-goog-upload-url, além de metadados como o tamanho esperado do bloco. - Transmitir e finalizar os bytes de vídeo:envie o payload de vídeo binário para
o endpoint
x-goog-upload-urlcomx-goog-upload-command: upload, finalize. Quando o upload é concluído, a resposta retorna oresource_name(customers/{customer_id}/youTubeVideoUploads/{video_upload_id}) criado.
Para uma descrição completa dos cabeçalhos HTTP usados no protocolo de upload de vídeo, consulte o seguinte exemplo de código:
# 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. Recuperar o estado de upload do vídeo
Depois de iniciar o upload de um vídeo, consulte o estado de processamento dele consultando os campos selecionáveis do recurso you_tube_video_upload (resource_name, video_upload_id, channel_id, video_id, state e video_privacy) com a GAQL até state = 'PROCESSED' (os campos INPUT_ONLY não podem ser selecionados na 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
Gerenciar uploads
Depois que o upload de um vídeo for concluído, você poderá usá-lo como um recurso de vídeo.
Usar o vídeo enviado
Depois que um vídeo atingir o estado PROCESSED, você poderá encontrar o ID de 11 caracteres
do vídeo do YouTube no campo video_id do recurso YouTubeVideoUpload.
Use este video_id para criar um YoutubeVideoAsset com
MutateAssets e vincular o nome do recurso resultante
(customers/{customer_id}/assets/{asset_id}) às suas campanhas ou anúncios:
Crie o
YoutubeVideoAssettransmitindoyoutube_video_idparaAssetService.MutateAssets:POST https://googleads.googleapis.com/v26/customers/{customer_id}/assets:mutate { "operations": [ { "create": { "name": "Product Launch Video", "youtubeVideoAsset": { "youtubeVideoId": "dQw4w9WgXcQ" } } } ] }Vincule o
Asseta umAssetGroupouAdGroupAd:Performance Max:crie um
AssetGroupAssetusandoAssetGroupAssetService.MutateAssetGroupAssetscomfield_typedefinido comoYOUTUBE_VIDEO: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" } } ] }Geração de demanda:faça referência a
customers/{customer_id}/assets/{asset_id}na listavideosde um objetoDemandGenVideoResponsiveAdInfoao chamarAdGroupAdService.MutateAdGroupAds: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" } } } } } ] }
Consulte os recursos atuais do
YOUTUBE_VIDEOusandoGoogleAdsService.SearchStream: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}'
Atualizar metadados
É possível atualizar a configuração de privacidade de um vídeo enviado por essa API usando
o método UpdateYouTubeVideoUpload com update_mask
definido como "video_privacy". Somente o campo video_privacy (PUBLIC ou
UNLISTED, para vídeos enviados a um brand channel de propriedade do anunciante) pode ser
atualizado após a criação. video_title, video_description, channel_id e
video_content_metadata são imutáveis. A inclusão de video_title ou
video_description na máscara de atualização falha com um
erro FieldError.IMMUTABLE_FIELD.
Remover uploads
Se você precisar excluir vídeos enviados com a API Google Ads, transmita os
customers/{customer_id}/youTubeVideoUploads/{video_upload_id} nomes de recursos
no campo resource_names do
método RemoveYouTubeVideoUpload. Isso remove o vídeo da Biblioteca de Recursos do Google Ads e do YouTube.