Embedded Signing Walkthrough

Give your users the ability to sign documents directly on your app or website using Dropbox Sign's embedded signing feature. The hellosign-embedded library adds the signing experience to your site using an iFrame. The documentation below describes requirements and setup steps for the embedded signing flow. Take a look at our white labeling guide to learn more about customizing your app's embedded signing.

Preliminary

  1. Create an API app (login required)
Important
The API app's domain name controls where the embedded iFrame can be opened. Embedded signing will only be possible on this and it's subdomains. However, you can use skipDomainVerification to embed requests created using test_mode.
  1. Save your API app's Client ID and API Key, which you'll need to use this feature.

Try Dropbox Sign Embedded

To get a feel for how our library works, you can use our Embedded Testing Tool to quickly test any of our Embedded flows without having to write a single line of JavaScript.

You can request a sample document, or use the custom sign_url that you'll generate in the Server Side section below.

Server Side

The very first step is to create an embedded signature request from your backend using our API and then fetch the associated url that will be used in the iFrame. Note that embedded signature requests use a different endpoint than non-embedded signature requests. Endpoint: /signature_request/create_embedded

Creating an Embedded Signature Request

curlphpjavapythonrubynodejsdotnet
Copy
Copied
curl 'https://api.hellosign.com/v3/signature_request/create_embedded' \
    -u 'SIGN_IN_AND_CREATE_API_KEY_FIRST:' \
    -F 'client_id=YOUR_CLIENT_ID' \
    -F 'file[0]=@file0.pdf' \
    -F 'file[1]=@file1.doc' \
    -F 'subject=My First embedded signature request' \
    -F 'message=Awesome, right?' \
    -F 'signers[0][email_address]=jack@example.com' \
    -F 'signers[0][name]=Jack' \
    -F 'signers[1][email_address]=jill@example.com' \
    -F 'signers[1][name]=Jill' \
    -F 'test_mode=1'
Copy
Copied
$client = new HelloSign\Client('SIGN_IN_AND_CREATE_API_KEY_FIRST');
$request = new HelloSign\SignatureRequest;
$request->enableTestMode();
$request->setSubject('My First embedded signature request with a template');
$request->setMessage('Awesome, right?');
$request->addSigner('jack@example.com', 'Jack');
$request->addSigner('jill@example.com', 'Jill');
$request->addFile($path_to_file_0_pdf);
$request->addFile($path_to_file_1_pdf);

$client_id = 'YOUR_CLIENT_ID';
$embedded_request = new HelloSign\EmbeddedSignatureRequest($request, $client_id);
$response = $client->createEmbeddedSignatureRequest($embedded_request);
Copy
Copied
SignatureRequest request = new SignatureRequest();
request.addFile(new File("file0.pdf"));
request.addFile(new File("file1.doc"));
request.setSubject("My First embedded signature request");
request.setMessage("Awesome, right?");
request.addSigner("jack@example.com", "Jack");
request.addSigner("jill@example.com", "Jill");
request.setTestMode(true);

String clientId = "YOUR_CLIENT_ID";
EmbeddedRequest embedReq = new EmbeddedRequest(clientId, request);

HelloSignClient client = new HelloSignClient("SIGN_IN_AND_CREATE_API_KEY_FIRST");
SignatureRequest newRequest = (SignatureRequest) client.createEmbeddedRequest(embedReq);
Copy
Copied
client = HSClient(api_key='SIGN_IN_AND_CREATE_API_KEY_FIRST')
client.send_signature_request_embedded(
    test_mode=True,
    client_id='YOUR_CLIENT_ID',
    subject='My First embedded signature request',
    message='Awesome, right?',
    signers=[
        { 'email_address': 'jack@example.com', 'name': 'Jack' },
        { 'email_address': 'jill@example.com', 'name': 'Jill' }
    ],
    files=['file0.pdf', 'file1.doc']
)
Copy
Copied
client.create_embedded_signature_request(
    :test_mode => 1,
    :client_id => 'YOUR_CLIENT_ID',
    :subject => 'My First embedded signature request',
    :message => 'Awesome, right?',
    :signers => [
        {
            :email_address => 'jack@example.com',
            :name => 'Jack'
        },
        {
            :email_address => 'jill@example.com',
            :name => 'Jill'
        }
    ],
    :files => ['file0.pdf', 'file1.doc']
)
Copy
Copied
const hellosign = require('hellosign-sdk')({ key: 'SIGN_IN_AND_CREATE_API_KEY_FIRST' });

const opts = {
  test_mode: 1,
  clientId: 'YOUR_CLIENT_ID',
  subject: 'NDA with Acme Co.',
  message: 'Please sign this NDA and then we can discuss more.?',
  signers: [
    {
      email_address: 'jack@example.com',
      name: 'Jack'
    },
    {
      email_address: 'jill@example.com',
      name: 'Jill'
    }
  ],
  files: ['NDA.pdf', 'Addendum.pdf']
};

hellosign.signatureRequest.createEmbedded(opts).then((res) => {
  // handle response
}).catch((err) => {
  // handle error
});
Copy
Copied
var client = new Client("SIGN_IN_AND_CREATE_API_KEY_FIRST");
var request = new SignatureRequest();
request.Subject = "My First embedded signature request";
request.Message = "Awesome, right?";
request.AddSigner("jack@example.com", "Jack");
request.AddSigner("jill@example.com", "Jill");
request.AddCc("lawyer@example.com");
request.AddFile("C:\Users\Me\My Documents\file0.pdf");
request.AddFile("C:\Users\Me\My Documents\file1.doc");
request.TestMode = true;
var response = client.CreateEmbeddedSignatureRequest(request, "YOUR_CLIENT_ID");
You just created an embedded signature request with two signers (Jack and Jill). In the response object, you will notice both signers have been assigned a unique signature_id. When one of these users visits your site, you will need to use the Dropbox Sign API generate a temporary sign_url using the signer's unique signature ID.
Important
In order to generate a sign_url the unique signature_id (per signer) will be needed and not the signature_request_id.

Generating a sign_url

Endpoint: /embedded/sign_url/{signature_id}

curlphpjavapythonrubynodejsdotnet
Copy
Copied
curl 'https://api.hellosign.com/v3/embedded/sign_url/78caf2a1d01cd39cea2bc1cbb340dac3' \
    -u 'SIGN_IN_AND_CREATE_API_KEY_FIRST:'
Copy
Copied
$client = new HelloSign\Client('SIGN_IN_AND_CREATE_API_KEY_FIRST');
$response = $client->getEmbeddedSignUrl('78caf2a1d01cd39cea2bc1cbb340dac3');
Copy
Copied
HelloSignClient client = new HelloSignClient("SIGN_IN_AND_CREATE_API_KEY_FIRST");
String signatureId = "78caf2a1d01cd39cea2bc1cbb340dac3";
EmbeddedResponse response = client.getEmbeddedSignUrl(signatureId);
String signUrl = response.getSignUrl();
Copy
Copied
client = HSClient(api_key='SIGN_IN_AND_CREATE_API_KEY_FIRST')
client.get_embedded_object('78caf2a1d01cd39cea2bc1cbb340dac3')
Copy
Copied
client.get_embedded_sign_url :signature_id => '78caf2a1d01cd39cea2bc1cbb340dac3'
Copy
Copied
const hellosign = require('hellosign-sdk')({ key: 'SIGN_IN_AND_CREATE_API_KEY_FIRST' });

hellosign.embedded.getSignUrl(signatureId).then((res) => {
  console.log('The sign url is: ' + res.embedded.sign_url);
}).catch((err) => {
  // handle error
});
Copy
Copied
var client = new Client("SIGN_IN_AND_CREATE_API_KEY_FIRST");
var response = client.GetSignUrl("78caf2a1d01cd39cea2bc1cbb340dac3");
Important
This call will return HTTP 409 if the signature request has already been signed by this signer orin the case of ordered signingthe request cannot be signed yet because it's not their turn. A successful response will return an object which contains a sign_url property. The sign_url is used to load the iFrame on your site using the hellosign-embedded.

Client Side

We provide a client-side library that handles the authorization and display of the embedded request using an iFrame. You can use this feature by adding a few lines of JavaScript code.

If you are using a modern module bundler with npm, simply install hellosign-embedded.
Copy
Copied
npm install hellosign-embedded

If you are not using a modern module bundler like npm, our library can be downloaded manually, compiled from source, or imported from our CDN.

In your app, import the hellosign-embedded module, instantiate a new client, then invoke open() with your sign_url and API client ID. Note that we're using skipDomainVerification when calling this method. You can learn more about that in the Domain Restriction section below.
Copy
Copied
import HelloSign from 'hellosign-embedded';

const client = new HelloSign();

client.open(claimUrl, {
  clientId: 'Your API client ID',
  skipDomainVerification: true
});

Note: It's recommended that you add the following to your document's <head> to avoid unexpected behavior on small screens. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">.

There are a number of options you can define as part of the second argument when calling open():
NameTypeDescription
requestingEmailstringThe email of the account issuing the signature request.

Note: This option is only necessary for 'Me and Others' type signature requests.

Example:
{
requestingEmail: alice@example.com
}
localestringThe locale code that will be used to determine which language the embedded request will be displayed in. For a list of Dropbox Sign's supported languages, visit our Languages page. If no locale is specified Dropbox Sign will attempt to determine the user's preferred language by their browser settings or fall back to English.

Note: Czech (CS_CZ) is only supported by Embedded Signing.

Example:
{
locale: HelloSign.locales.ZH_CN
}
redirectTostringWhere the user will be redirected after sending the signature request.

Example:
{
redirectTo: 'http://example.com'
}
allowCancelbooleanWhether the user should be able to close the iFrame without finishing the request. Default: true.

Example:
{
allowCancel: false
}
debugbooleanAllows debug output to print to the console. Default: false.

For even more detailed debug output, run localStorage.debug = 'hellosign-embedded:*'; in your developer console and refresh the page.

Example:
{
debug: true
}
skipDomainVerificationbooleanWhether or not to skip the domain verification step. Default: false.

Note: This will only be honored if the signature request was created with test_mode=1.

Example:
{
skipDomainVerification: true
}
timeoutnumberHow long (in milliseconds) to wait for the app to initialize before aborting. Default: 30000 (30 seconds).

Example:
{
timeout: 10000
}
containerHTMLElementBy default a modal will be opened, but by specifying container you can choose a DOM element on the page in which the iFrame will be embedded.

Example:
{
container: document.getElementById('sign-here')
}

Additional notes

App Approval

In order to ensure that integrations adhere to eSignature regulations and best practices, an app approval is needed prior to moving into production for all customers implementing embedded signing, embedded requesting, embedded templates, and OAuth workflows.

Important

You will still be able to use your app in test mode until it gets approved. Only live/production activity requires approval.

Please refer to the App Approval Section for more detailed information about getting your app approved.

Domain Restriction

When the iFrame is loaded, it will verify the domain of the parent window and ensure it matches the domain name of the API app specified by the client ID. If the domain does not match, the page won't be loaded.

You can disable domain restriction for easier development:

Copy
Copied
client.open(signUrl, {
  // ...
  skipDomainVerification: true
});
This will allow you to use development domains, like localhost. See the documentation for open() method in the section above.

HTTPS Required

The host page must be served over HTTPS. The iFrame is also loaded over HTTPS, and due to browser security restrictions it will not be able to communicate with the parent window if it is not HTTPS. This communication is required to enable features such as iFrame callbacks and closing the iFrame.

To make development easier, the page will still load if the parent window is served over HTTP, however an alert will be displayed to notify you of this requirement. Switch to HTTPS to prevent this alert from being displayed.

Redirection

If a redirect url is specified, the iFrame will redirect users to it after they send the document(s). Data from the sign event will be appended to the url query string.

Signature Links

Signature URLs are only valid for 60 minutes after /embedded/sign_url has been called and expire as soon as they're accessed.

It is best practice to wait until your signer hits the page before generating the sign_url so the link doesn't expire before the signer is ready. However, since the signature_id itself does not expire, a fresh sign_url can always be generated.

Text Tags

The embedded functionality can be used in conjunction with Dropbox Sign Text Tags.

Client Side Events

There are a number of events that the client may emit. To listen to these events, pass the event name and a callback function to on(). An string enumeration of available events can also be found under HelloSign.events.
Copy
Copied
client.on('sign', (data) => {
  console.log('The document has been signed!');
  console.log('Signature ID: ' + data.signatureId);
});

Here are a list of possible events:

EventDescriptionData
createTemplateEmitted when the user creates the signature request template.
{
templateId,
templateInfo {
title,
message,
signerRoles,
ccRoles
}
}
openEmitted when the embedded window has opened.
{
url,
iFrameUrl
}
cancelEmitted when the template was canceled by the user by either pressing the close button or selecting "close" from the dropdown list.
finishEmitted when the user has finished the embedded template flow without cancelling.
messageEmitted when embedded has received a cross-origin window message from the app.
{
type,
payload
}
closeEmitted when the embedded window has closed.
errorEmitted when the app encounters an error.
{
signatureId,
code
}