Upload an object with HTML forms

This page describes how to use HTML forms, which allow yourusers to upload files to your bucket. When you create an HTML form, it'srecommended that you create apolicy document, which defines conditionsthat upload requests must meet. HTML forms utilize the XML objectPOST API.

The uploaded object replaces any existing object with the same name. Fortips on uploading to Cloud Storage, seebest practices. For informationaboutPOST object requests using the legacy signingprocess, seePOST Object with the V2 signing process.

Note:Signatures are used in HTML forms that have an associated policydocument. HTML forms do not supportsigned URLs.

Query string parameters

This request does not include query string parameters.

Form fields

You can create an HTML form by defining the form fields described below.

FieldDescriptionRequired
aclThe predefined ACL that you want to apply to the object that is being uploaded. If you do not specify this field the bucket'sdefault ACL is applied.No
bucketThe name of the bucket that you want to upload to. If you include this field, it must match the bucket name you specify in theaction attribute.No
Cache-ControlThe cache control for the object. You can only set cache control for an object that is accessible to all users. For instance, an object's ACL must bepublic-read orpublic-read-write to be able to set the cache-control.No
Content-DispositionSpecifies how the object data should be transmitted. For example, aContent-Disposition value ofinline means that the object should be displayed immediately.No
Content-EncodingThe compression algorithm for the object, such asgzip.No
Content-LengthThe size of the uploaded file, in bytes.No
Content-TypeThe MIME type of the file you are uploading via the form. If you do not specify a content type, the Cloud Storage system defaults toapplication/octet-stream when it serves the content.No
ExpiresAnISO8601 timestamp that specifies the date and time before an object is considered stale by the browser.No
fileThe file you are uploading. Must be the last field in the form. You can upload only one object per request.Yes
keyThename of the object that you are uploading. You can also use the ${filename} variable if a user is providing a file name.Yes
policy

The security policy that describes what can and cannot be uploaded in the form. The policy document must be Base64 encoded. Seepolicy documents for more information.

If you do not provide a security policy, requests are considered to be anonymous and will only work with buckets that have grantedWRITE orFULL_CONTROL permission to anonymous users.

No
success_action_redirectA URL that users are redirected to when an upload is successful. If you do not provide a URL, Cloud Storage responds with the status code that you specified insuccess_action_status.No
success_action_statusThe status code that you want Cloud Storage to respond with when an upload is successful. The default is 204, but you can change this to 200 or 201. If you choose 200 or 204, Cloud Storage returns an empty document with those status codes. If you choose 201, Cloud Storage returns an XML document with the elements that are described in Response Body Elements.No
x-goog-algorithmThe signing algorithm used to create thesignature associated with your policy document. Possible values areGOOG4-HMAC-SHA256 andGOOG4-RSA-SHA256Only if you specify apolicy
x-goog-credentialThe credentials used to create thesignature associated with your policy document.x-goog-credential has the formAccessKeyId/CredentialScope, where:
  • AccessKeyId is the email address of the entity responsible for creating the signature. This entity is typically aservice account, but may also be a user account.
  • CredentialScope is thecredential scope used in the signature.
Only if you specify apolicy
x-goog-custom-timeA user-specified date and time in theRFC 3339 formatYYYY-MM-DD'T'HH:MM:SS.SS'Z'.No
x-goog-dateThe current date, in theISO 8601 basic formatYYYYMMDD'T'HHMMSS'Z'.Only if you specify apolicy
x-goog-signatureThesignature associated with your policy document.Only if you specify apolicy
x-goog-meta-*A field for custom metadata. You can use this to specify any additional metadata that is not provided by the other form fields. For example,x-goog-meta-reviewer: jane orx-goog-meta-project-manager: john is custom metadata.No

Response body elements

The following response body elements are returned in an XML document only ifyou setsuccess_action_status to 201.

ElementDescription
BucketBucket in which the object was stored.
ETagHTTP 1.1 entity tag for the object.
KeyThe object's name.
LocationThe URI for the object.

Example of how to create an HTML form

The following example shows you how to create an HTML form to upload an object,using a signature that's created with the V4 policy signing process.

The form must be UTF-8 encoded. You can specify form encoding in the form's HTMLhead tag or by using theContent-Type request header.

Yourform tag must specify the following three items:

  • An action.

    Theaction attribute specifies an XML APIrequest endpoint.

    Valid endpoints includehttps://BUCKET_NAME.storage.googleapis.com,https://storage.googleapis.com/BUCKET_NAME, andCNAME redirects.

  • A method.

    Themethod attribute specifies the method that you are using to submitthe form. It must bepost.

  • An enclosure type.

    Theenctype attribute specifies the enclosure type you are using and mustalways bemultipart/form-data.

The following is an example HTML form, which uses apolicy document that'sspecified by thepolicy form field.

HTML

<form    action="https://storage.googleapis.com/travel-maps"    method="post"    enctype="multipart/form-data">  <input      type="text"      name="key"      value="test-object">  <input      type="hidden"      name="Content-Type"      value="image/jpeg">  <input      type="hidden"      name="success_action_redirect"      value="https://www.example.com/success_notification.html">  <input      type="hidden"      name="policy"      value="eyJjb25kaXRpb25zIjpbey...">  <input      type="hidden"      name="x-goog-algorithm"      value="GOOG4-RSA-SHA256">  <input      type="hidden"      name="x-goog-credential"      value="example_account@example_project.iam.gserviceaccount.com/20191102/us-central1/storage/goog4_request">  <input      type="hidden"      name="x-goog-date"      value="20191102T043530Z">  <input      type="hidden"      name="x-goog-signature"      value="58bc39b8f604ee1f18171f...">  <input      name="file"      type="file">  <input      type="submit"      value="Upload"></form>

Client libraries

C++

For more information, see theCloud StorageC++ API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

namespacegcs=::google::cloud::storage;using::google::cloud::StatusOr;[](gcs::Clientclient,std::stringconst&bucket_name,std::stringconst&object_name,std::stringconst&signing_account){autodocument=client.GenerateSignedPostPolicyV4(gcs::PolicyDocumentV4{bucket_name,object_name,/*expiration=*/std::chrono::minutes(10),},gcs::AddExtensionFieldOption("x-goog-meta-test","data"),gcs::SigningAccount(signing_account));if(!document)throwstd::move(document).status();// Create the HTML form for the computed policy.std::ostringstreamos;os <<"<form action='" <<document->url <<"' method='POST'"     <<" enctype='multipart/form-data'>\n";for(autoconst&field:document->required_form_fields){os <<"  <input name='" <<field.first <<"' value='" <<field.second       <<"' type='hidden' />\n";}os <<"  <input type='submit' value='Upload File' /><br />\n"     <<"  <input type='file' name='file' /><br />\n"     <<"</form>";std::cout <<"A sample HTML form:\n" <<os.str() <<"\n";}

C#

For more information, see theCloud StorageC# API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

// Create a signed post policy which can be used to upload a specific object and// expires in 1 hour after creation.UrlSignerurlSigner=UrlSigner.FromCredential(credential);UrlSigner.Optionsoptions=UrlSigner.Options.FromDuration(TimeSpan.FromHours(1)).WithSigningVersion(SigningVersion.V4).WithScheme("https");UrlSigner.PostPolicypostPolicy=UrlSigner.PostPolicy.ForBucketAndKey(bucketName,objectName);postPolicy.SetCustomField(UrlSigner.PostPolicyCustomElement.GoogleMetadata,"x-goog-meta-test","data");UrlSigner.SignedPostPolicysignedPostPolicy=awaiturlSigner.SignAsync(postPolicy,options);// Create an HTML form including all the fields in the signed post policy.StringBuilderform=newStringBuilder();form.AppendLine($"<form action=\"{signedPostPolicy.PostUrl}\" method=\"post\" enctype=\"multipart/form-data\">");foreach(varfieldinsignedPostPolicy.Fields){form.AppendLine($"<input type=\"hidden\" name=\"{field.Key}\" value=\"{field.Value}\">");}// Include the file element. It should always be the last element in the form.form.AppendLine("<input name=\"file\" type=\"file\">");form.AppendLine("<input type=\"submit\" value=\"Upload\">");form.AppendLine("</form>");// You can now save the form to file and serve it as static content// or send it as the response to a request made to your application.File.WriteAllText("PostPolicySimple.html",form.ToString());

Java

For more information, see theCloud StorageJava API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

importcom.google.cloud.storage.BlobInfo;importcom.google.cloud.storage.PostPolicyV4;importcom.google.cloud.storage.Storage;importcom.google.cloud.storage.StorageOptions;importjava.util.Map;importjava.util.concurrent.TimeUnit;publicclassGenerateSignedPostPolicyV4{/**   * Generating a signed POST policy requires Credentials which implement ServiceAccountSigner.   * These can be set explicitly using the Storage.PostPolicyV4Option.signWith(ServiceAccountSigner)   * option. If you don't, you could also pass a service account signer to StorageOptions, i.e.   * StorageOptions().newBuilder().setCredentials(ServiceAccountSignerCredentials). In this example,   * neither of these options are used, which means the following code only works when the   * credentials are defined via the environment variable GOOGLE_APPLICATION_CREDENTIALS, and those   * credentials are authorized to sign a policy. See the documentation for   * Storage.generateSignedPostPolicyV4 for more details.   */publicstaticvoidgenerateSignedPostPolicyV4(StringprojectId,StringbucketName,StringblobName){// The ID of your GCP project// String projectId = "your-project-id";// The ID of the GCS bucket to upload to// String bucketName = "your-bucket-name"// The name to give the object uploaded to GCS// String blobName = "your-object-name"Storagestorage=StorageOptions.newBuilder().setProjectId(projectId).build().getService();PostPolicyV4.PostFieldsV4fields=PostPolicyV4.PostFieldsV4.newBuilder().setCustomMetadataField("test","data").build();PostPolicyV4policy=storage.generateSignedPostPolicyV4(BlobInfo.newBuilder(bucketName,blobName).build(),10,TimeUnit.MINUTES,fields);StringBuilderhtmlForm=newStringBuilder("<form action='"+policy.getUrl()+"' method='POST' enctype='multipart/form-data'>\n");for(Map.Entry<String,String>entry:policy.getFields().entrySet()){htmlForm.append("  <input name='"+entry.getKey()+"' value='"+entry.getValue()+"' type='hidden' />\n");}htmlForm.append("  <input type='file' name='file'/><br />\n");htmlForm.append("  <input type='submit' value='Upload File'/><br />\n");htmlForm.append("</form>\n");System.out.println("You can use the following HTML form to upload an object to bucket "+bucketName+" for the next ten minutes:");System.out.println(htmlForm.toString());}}

Go

For more information, see theCloud StorageGo API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

import("context""fmt""html/template""io""time""cloud.google.com/go/storage")// form is a template for an HTML form that will use the data from the signed// post policy.varform=`<form action="{{ .URL }}" method="POST" enctype="multipart/form-data">{{- range $name, $value := .Fields }}<input name="{{ $name }}" value="{{ $value }}" type="hidden"/>{{- end }}<input type="file" name="file"/><br /><input type="submit" value="Upload File" name="submit"/><br /></form>`vartmpl=template.Must(template.New("policyV4").Parse(form))// generateSignedPostPolicyV4 generates a signed post policy.funcgenerateSignedPostPolicyV4(wio.Writer,bucket,objectstring)(*storage.PostPolicyV4,error){// bucket := "bucket-name"// object := "object-name"ctx:=context.Background()client,err:=storage.NewClient(ctx)iferr!=nil{returnnil,fmt.Errorf("storage.NewClient: %w",err)}deferclient.Close()metadata:=map[string]string{"x-goog-meta-test":"data",}// Generating a signed POST policy requires credentials authorized to sign a URL.// You can pass these in through PostPolicyV4Options with one of the following options://    a. a Google service account private key, obtainable from the Google Developers Console//    b. a Google Access ID with iam.serviceAccounts.signBlob permissions//    c. a SignBytes function implementing custom signing// In this example, none of these options are used, which means the// GenerateSignedPostPolicyV4 function attempts to use the same authentication// that was used to instantiatethe Storage client. This authentication must// include a private key or have iam.serviceAccounts.signBlob permissions.opts:=&storage.PostPolicyV4Options{Expires:time.Now().Add(10*time.Minute),Fields:&storage.PolicyV4Fields{Metadata:metadata,},}policy,err:=client.Bucket(bucket).GenerateSignedPostPolicyV4(object,opts)iferr!=nil{returnnil,fmt.Errorf("storage.GenerateSignedPostPolicyV4: %w",err)}// Generate the form, using the data from the policy.iferr=tmpl.Execute(w,policy);err!=nil{returnpolicy,fmt.Errorf("executing template: %w",err)}returnpolicy,nil}

Node.js

For more information, see theCloud StorageNode.js API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

/** * TODO(developer): Uncomment the following lines before running the sample. */// The ID of your GCS bucket// const bucketName = 'your-unique-bucket-name';// The ID of your GCS file// const fileName = 'your-file-name';// Imports the Google Cloud client libraryconst{Storage}=require('@google-cloud/storage');// Creates a clientconststorage=newStorage();asyncfunctiongenerateV4SignedPolicy(){constbucket=storage.bucket(bucketName);constfile=bucket.file(fileName);// These options will allow temporary uploading of a file// through an HTML form.constexpires=Date.now()+10*60*1000;//  10 minutesconstoptions={expires,fields:{'x-goog-meta-test':'data'},};// Get a v4 signed policy for uploading fileconst[response]=awaitfile.generateSignedPostPolicyV4(options);// Create an HTML form with the provided policyletoutput=`<form action="${response.url}" method="POST" enctype="multipart/form-data">\n`;// Include all fields returned in the HTML form as they're requiredfor(constnameofObject.keys(response.fields)){constvalue=response.fields[name];output+=`  <input name="${name}" value="${value}" type="hidden"/>\n`;}output+='  <input type="file" name="file"/><br />\n';output+='  <input type="submit" value="Upload File"/><br />\n';output+='</form>';console.log(output);}generateV4SignedPolicy().catch(console.error);

PHP

For more information, see theCloud StoragePHP API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

use Google\Cloud\Storage\StorageClient;/** * Generates a v4 POST Policy to be used in an HTML form and echo's form. * * @param string $bucketName The name of your Cloud Storage bucket. *        (e.g. 'my-bucket') * @param string $objectName The name of your Cloud Storage object. *        (e.g. 'my-object') */function generate_v4_post_policy(string $bucketName, string $objectName): void{    $storage = new StorageClient();    $bucket = $storage->bucket($bucketName);    $response = $bucket->generateSignedPostPolicyV4(        $objectName,        new \DateTime('10 min'),        [            'fields' => [                'x-goog-meta-test' => 'data'            ]        ]    );    $url = $response['url'];    $output = "<form action='$url' method='POST' enctype='multipart/form-data'>" . PHP_EOL;    foreach ($response['fields'] as $name => $value) {        $output .= "  <input name='$name' value='$value' type='hidden'/>" . PHP_EOL;    }    $output .= "  <input type='file' name='file'/><br />" . PHP_EOL;    $output .= "  <input type='submit' value='Upload File' name='submit'/><br />" . PHP_EOL;    $output .= '</form>' . PHP_EOL;    echo $output;}

Python

For more information, see theCloud StoragePython API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

importdatetimefromgoogle.cloudimportstoragedefgenerate_signed_post_policy_v4(bucket_name,blob_name):"""Generates a v4 POST Policy and prints an HTML form."""# bucket_name = 'your-bucket-name'# blob_name = 'your-object-name'storage_client=storage.Client()policy=storage_client.generate_signed_post_policy_v4(bucket_name,blob_name,expiration=datetime.timedelta(minutes=10),fields={'x-goog-meta-test':'data'})# Create an HTML form with the provided policyheader="<form action='{}' method='POST' enctype='multipart/form-data'>\n"form=header.format(policy["url"])# Include all fields returned in the HTML form as they're requiredforkey,valueinpolicy["fields"].items():form+=f"  <input name='{key}' value='{value}' type='hidden'/>\n"form+="  <input type='file' name='file'/><br />\n"form+="  <input type='submit' value='Upload File' /><br />\n"form+="</form>"print(form)returnform

Ruby

For more information, see theCloud StorageRuby API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, seeSet up authentication for client libraries.

defgenerate_signed_post_policy_v4bucket_name:,file_name:# The ID of the GCS bucket to upload to# bucket_name = "your-unique-bucket-name"# The name to give the object uploaded to GCS# file_name = "your-file-name"require"google/cloud/storage"storage=Google::Cloud::Storage.newbucket=storage.bucketbucket_namepost_object=bucket.generate_signed_post_policy_v4file_name,expires:600,fields:{"x-goog-meta-test"=>"data"}html_form="<form action='#{post_object.url}' method='POST' enctype='multipart/form-data'>\n"post_object.fields.eachdo|name,value|html_form+="  <input name='#{name}' value='#{value}' type='hidden'/>\n"endhtml_form+="  <input type='file' name='file'/><br />\n"html_form+="  <input type='submit' value='Upload File'/><br />\n"html_form+="</form>\n"puts"You can use the following form to upload an object to bucket#{bucket_name} for the next 10 minutes:\n"putshtml_formpost_objectend

As a best practice you should use theExpect: 100-continue headerwithPOST requests. This lets you verify that the server will handle therequest before you send the object. If you receive a status code100 Continueyou should proceed with the request. If you receive a status code417 Expectation Failed then you shouldn't send the object.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.