Collect consent

Collect consent from your users integrated with all forms.

Make sure that you have followed the setup instructions in the Getting started section to include the legal.js library on the page with your form. Note that, if your form is in an iframe, then legal.js must be included in the HTML of the iframe, otherwise legal.js will not be available there.

To collect consent using legal.js, you must specify where you want to insert the widget. You can use an existing element as the target, or add a new one to serve as the target. The target element is specified by a CSS selector in the targetElementSelector option.

Important note: The target element must be inside the <form> element that requires consent. This is currently a technical requirement for legal.js to function, and an error like "Unable to find signup form. Aborting setup." will be logged to the browser console if this is not the case.

You can use any standard CSS selector to specify the target element. It is important that your selector matches exactly one element; if it does not, legal.js will not work, and will log an error to the browser console.

You can perform a simple test by using the standard Document.querySelector() method in your browser console, passing it the same selector that you intend to pass to targetElementSelector and verifying that the matched element is the one you expect. Note that, if your form is in an iframe, you will need to run this test in the console of the iframe, not the console of the surrounding page.

Example integration

If you have a form with a structure like this:

<form>
    <label>Name:
        <input type="text" name="fullname" />
    </label>
    <label>Email:
        <input type="email" name="email" />
    </label>
    <div id="target-element-id"></div>
    <input type="submit" name="continue" value="Continue" />
</form>

...with an empty <div> as the target element, whose id attribute is set to target-element-id, then you can use a snippet of JavaScript like this to enable the widget:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
    });
</script>

The target element is replaced with our widget, so it is sufficient to use an empty <div> element as shown here.

Advanced integration

If you cannot change the HTML of your page, you can still use our widget. See the section on targeting an existing element.

If you have several buttons with a submit action (such as updating a cart as well as checking out), see the section on multiple submit buttons.

Target an existing element

If you cannot change the HTML of your page, legal.widget() offers an option to add the widget before or after an existing target element that you choose.

The following code searches for a target element with the ID target-element-id and replaces that element with the widget:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
    });
</script>

If you need to preserve the target element, you can use theinsertMode option to change how and where the widget is placed in relation to the target element, like so:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        insertMode: "after",
    });
</script>

You can change the insertion method to one of the following options:

Insertion mode

Description

replace (Default)

Replaces the specified target element with the widget

after

Inserts the widget after the specified target element

before

Inserts the widget before the specified target element

Identifying the user

When your users interact with Openli, we assign a unique ID to them. This is imperfect, because it can vary under many circumstances, for example when they use another browser. To allow us to identify your users precisely, you can provide us with the same unique identifier that you use internally when identifying them. This will avoid the creation of multiple records in our audit trail for the same user.

To do this, simply pass the identifier option with your unique identifier as its value. Here is an example of identifying your user when calling legal.widget():

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        identifier: "Your unique user ID",
    });
</script>

We recommend using database IDs or similar unchanging unique keys for the identifier.

Styling options for the widget

You can change the width of the outermost border, and the amount of outermost padding, by specifying the outerBorderWidth and outerPaddingSize options:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        outerBorderWidth: 2, // Value in pixels
        outerPaddingSize: 5, // Value in pixels
    });
</script>

To entirely remove the outermost border and padding, set both options to 0 like so:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        outerBorderWidth: 0, // Value in pixels
        outerPaddingSize: 0, // Value in pixels
    });
</script>

This approach can work well in combination with a wrapper element to style the widget more seamlessly within your existing page. In your page's HTML, include a wrapper element around the target element:

<form>
    <label>Name:
        <input type="text" name="fullname" />
    </label>
    <label>Email:
        <input type="email" name="email" />
    </label>
    <div id="your-wrapper-to-style">
        <div id="target-element-id"></div>
    </div>
    <input type="submit" name="continue" value="Continue" />
</form>

You will now be able to specify custom border, padding, margin, and other styles on the wrapper element.

Please note: Openli regularly update the widget to provide improved legal compliance and a better user-experience. You must therefore not assume that the contents of the widget will never change, and you must not constrain the height of the widget.

Explicitly marking required fields

You can choose to show an asterisk next to required fields so users can visually determine which fields are required. This can be done by specifying the following option:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        markRequiredFields: true,
    });
</script>

This will include an asterisk after a required field, as seen below:

Required fields in our widget also have annotations to help assistive technologies like screen-readers to guide their users more accessibly.

Collect additional user information

The widget also enables you to collect your users' name and email when they sign up to help identify them, using the nameInputSelector and emailInputSelector options, respectively. This naturally assumes that your form contains input fields for name and email address.

Using our example form, the following options will target the name and email fields using CSS selectors:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        nameInputSelector: '[name="fullname"]', 
        emailInputSelector: '[name="email"]',
    });
</script>

The widget will then associate the values from those input fields with the consent the user gives. You may use either or both of these options, so if you only collect an email address, you can use only the emailInputSelector option.

Note: Collecting name and email does not need to be done when your user signs up. Please see the next section for more information.

Collect user information separately

The legal.user() method lets you attach a full name and an email address to the current user independently of collecting consent. When using this method, the user will be updated in our system with the name and email you define.

Note: To use the current version of this method, you must also call legal.load() as shown below.

<script>
    legal.load("Your widget's public-key");

    legal.user({
        name: "John Doe",
        email: "john.doe@example.com",
    });
</script>

Of course, if your form already provided this information to the consent widget, there is no need to provide it again. However, legal.user() is useful if the user changes their email address or their name.

If you are integrating with a form that already has one or more checkboxes to indicate consent to a particular type of agreement, you can specify that legal.js should control them. This can be useful for providing immediate integration with your existing systems.

The currently-supported categories for consent collection are:

  • Terms of service

  • Privacy policy

  • Email marketing

For a form with the following structure:

<form>
    <label for="acme-terms">I agree to ACME's terms of service</label>
    <input type="checkbox" name="acme-terms" id="acme-terms">

    <label>I agree to ACME's privacy policy
        <input type="checkbox" name="acme-privacy">
    </label>

    <span id="email-marketing-label">
        Yes, I want to receive email marketing from ACME
    </span>
    <input
        type="checkbox"
        name="acme-email-marketing"
        aria-labelledby="email-marketing-label"
    >

    <div id="target-element-id"></div>

    <input type="submit" name="signup" value="Sign up">
</form>

This would be the appropriate configuration to control the existing checkboxes, using the controlledConsentFields option of legal.widget():

legal.widget({
    type: "signup",
    widgetPublicKey: "Your widget's public-key",
    targetElementSelector: "#target-element-id",
    controlledConsentFields: {
        // Any CSS selector that matches a single element in your form may be used.
        termsOfService: "#acme-terms",
        privacyPolicy: '[name="acme-privacy"]',
        emailMarketing: '[aria-labelledby="email-marketing-label"]',
    },
})

Using this option will also automatically hide the checkbox field and any semantically-related labels in the same form, making integration as simple as possible. The labels that will be hidden are:

  • Labels that wrap the checkbox.

  • Labels that have a for attribute with a value corresponding to the label's id attribute.

  • Any other elements (e.g. span) acting as labels that have an id attribute corresponding to an aria-labelledby attribute on the checkbox.

Validation

We perform basic front-end validation to ensure that the user has given the required consent for your form to be submitted.

However, for security reasons, when you process the submitted form on your server, you should validate that the form input named -penli-consent has a value of on, the default value of a checkbox.

Defining the name of the validation field

If required, you can set the name of the validation field by specifying the validationFieldName option.

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        validationFieldName: "consent-validation",
    });
</script>

In this example, the name of the validation input field would not be the default openli-consent, but consent-validation.

Specifying which buttons legal.js should watch

By default, all submit-buttons in your form will be watched by legal.js, to ensure that the user gives consent before submitting. This table gives an overview of the standard behaviour of buttons in a form, and whether legal.js watches them:

Example button within <form>

Can submit form?

Is watched by default?

<input type="submit" value="Submit" />

Yes

Yes

<input type="reset" value="Reset" />

No

No

<button>Submit</button>

Yes

Yes

<button type="submit">Submit</button>

Yes

Yes

<button type="">Submit</button>

Yes

Yes

<button type="button">Non-submitting</button>

No

No

<button type="reset">Non-submitting</button>

No

No

There are situations when this might not be what you want. Using the submitButtonSelectors option you can provide a standard CSS selector that matches only the button, or buttons, that legal.js should watch.

This option uses the standard Document.querySelectorAll() method internally, and it supports any element, so you can target clickable non-button elements if you use those instead of standard buttons to submit your form.

Important: when using the submitButtonSelectors option, legal.js will watch only the elements that are matched by the selectors you provide, and will not include your form's default submit buttons if they do not match.

When your form has multiple submit-buttons

You might want to implement consent in a form with multiple submit-buttons, only some of which should be watched by legal.js. For example, you might have an "Update items" button that does not enter the checkout flow, and therefore does not require that the user gives consent to your agreements.

<form>
    <div id="target-element-id"></div>
    <button name="updateItems">Update items</button>
    <input type="submit" name="checkout" value="Go to checkout" />
</form>

In this case, you probably do not want the "Update items" button to be dependent on the user consenting to your agreements.

By setting the submitButtonSelectors option to an appropriate CSS selector, you can target only the button (or buttons) that legal.js should watch:

<script>
    legal.widget({
        type: "signup",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        // Matches all `input` elements anywhere within
        // a `form` element, and only when the `input` has
        // a `name` attribute with the value "checkout".
        submitButtonSelectors: 'form input[name="checkout"]',
    });
</script>

When your submit-button is outside your form

It is also possible to specify that legal.js should watch one or more buttons outside your form. Simply use an appropriate CSS selector to select the button(s).

For a document structure like this:

<form>
    <div id="target-element-id"></div>
    <button name="updateItems">Update items</button>
</form>
<input type="submit" name="checkout" value="Go to checkout" />

You might pass submitButtonSelectors an appropriate selector like so:

<script>
    legal.widget({
        type: "submit",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        // Matches all `input` elements anywhere within
        // the document, and only when the `input` has
        // a `name` attribute with the value "checkout".
        submitButtonSelectors: 'input[name="checkout"]',
    });
</script>

You can of course use the flexibility of CSS selectors to match buttons inside and outside your form, by using multiple selectors:

<script>
    legal.widget({
        type: "submit",
        widgetPublicKey: "Your widget's public-key",
        targetElementSelector: "#target-element-id",
        // Matches all `button` elements anywhere within
        // the document, and only when the `button` has
        // a `name` attribute with the value "checkout".
        // Also matches all `input` elements anywhere within
        // a `form` element, and only when the `input` has
        // a `type` attribute with the value "submit".
        submitButtonSelectors: 'button[name="checkout"], form input[type="submit"]',
    });
</script>

It is important to test that the selectors you pass to the submitButtonSelectors option match only the buttons you want legal.js to watch, and that they match all of them.

You can perform a simple test by using the standard Document.querySelectorAll() method in your browser console, passing it the same selectors that you intend to pass to submitButtonSelectors and verifying that the list of matched elements is what you expect.

Last updated