Skip to main content
Solved

Hosted Page - Update Both Preferences and Unsubscribe

  • February 13, 2025
  • 6 replies
  • 60 views

Forum|alt.badge.img

I'm working on a Klaviyo hosted page where users can update their email preferences and unsubscribe from email marketing because I want customer to just click on unsubscribe page to do unsubscribe and update preference. However, I'm facing an issue:

  • If a user checks both $unsubscribe and nocatalog, Klaviyo only processes the unsubscribe action but doesn't update nocatalog.
  • I want the user to be able to update both preferences and unsubscribe at the same time.

Here's my current template that I edit from example code in https://help.klaviyo.com/hc/en-us/articles/115005077067 :

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Update Preferences</title>
    <style type="text/css">
        body {
            font-family: "Helvetica Neue", Arial, sans-serif;
            background-color: #f9f9f9;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }

        .form-container {
            background-color: #ffffff;
            padding: 40px;
            border-radius: 5px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            width: 100%;
            max-width: 500px;
            text-align: center;
        }

        .form-container img {
            max-width: 100%;
            width: 300px;
            margin-bottom: 20px;
        }

        .form-container h1 {
            margin-bottom: 20px;
        }

        .form-container label {
            display: block;
            text-align: left;
            margin: 10px 0 5px;
            font-weight: bold;
        }

        .form-container input[type="text"],
        .form-container input[type="email"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 3px;
            font-size: 16px;
        }

        .form-container .checkbox-group {
            text-align: left;
            margin-top: 1rem;
        }

        .form-container .checkbox-group label {
            font-weight: normal;
            display: flex;
            align-items: center;
        }

        .form-container .checkbox-group input {
            margin-right: 8px;
        }

        .form-container button {
            width: 100%;
            padding: 12px;
            margin-top: 20px;
            font-size: 16px;
            color: #fff;
            background-color: #c13535;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }

        .form-container .unsubscribe {
            background-color: transparent;
            color: #282828;
            margin-top: 10px;
        }
    </style>
</head>

<body>
    <form class="form-container" action="" id="preferences_form" method="POST" role="form" class="form-horizontal">
      {% if form.non_field_errors %}
            <div class="alert alert-danger">
               {% for error in form.non_field_errors %}
               {{ error }}{% if not forloop.last %}<br />{% endif %}
               {% endfor %}
            </div>
            {% endif %}
            <input type="hidden" name="$fields" value="nocatalog" />

        <h1>Update Preferences</h1>
        <label for="email">Email <span style="color: red;">*</span></label>
        <input type="email" name="$email" id="email"
            value="{% if request.POST|lookup:'$email' %}{{ request.POST|lookup:'$email' }}{% else %}{{ person.email|default:'' }}{% endif %}"
            required />
        {% if form.errors|lookup:'$email' %}
        <p class="help-block">{% for error in form.errors|lookup:'$email' %}{{ error }}{% endfor %}</p>
        {% endif %}

        <label for="first-name">First Name <span style="color: red;">*</span></label>
        <input type="text" name="$first_name" id="first-name" value="{% if request.POST|lookup:'$email' %}{{ request.POST|lookup:'$first_name' }}{% else %}{{ person.first_name|default:'' }}{% endif %}" required />

        <label for="last-name">Last Name <span style="color: red;">*</span></label>
        <input type="text" name="$last_name" id="last-name" value="{% if request.POST|lookup:'$email' %}{{ request.POST|lookup:'$last_name' }}{% else %}{{ person.last_name|default:'' }}{% endif %}" required />

        <div class="checkbox-group">
            <label><input type="checkbox" name="$unsubscribe" value="true"> Unsubscribe me from email marketing.</label>
            <label><input type="checkbox" name="nocatalog" value="true" {% if 'true' in person.nocatalog or 'true' in request.POST.nocatalog %}checked="checked" {% elif not person.nocatalog and not request.POST.nocatalog %}{% endif %} />Do not send me printed catalogs any longer.</label>
            <label><input type="checkbox" name="$double_optin" value="true"> Please include me more often for email messages.</label>
        </div>

        <button type="submit">Update Preferences</button>
    </form>
    <!-- /container -->
      <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
      <!-- Latest compiled and minified JavaScript -->
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.13.1/jquery.validate.min.js"></script>
    <script>
        $(function() {
            $('#preferences_form').validate({
                rules: {
                    $email: {
                        required: true
                    }
                },
                messages: {
                    $email: 'Please enter your email address.',
                    $first_name: 'Please enter your first name.',
                    $last_name: 'Please enter your last name.'
                }
            });
            // Toggle validation based on selection.
            $('input[name="$unsubscribe"]').on('change', function() {
                $('form .form-actions button[type="submit"]').toggleClass('cancel', $(this).is(':checked'));
            });
        });
    </script>
</body>

</html>

 

Best answer by PatiphonO

emma.owens wrote:

Hi ​@PatiphonO ! 

Just following up on this - were you able to figure out how to set up the HTML so that it updates both preferences and unsubscribe at the same time? 

Yes, for unsubscribing, I just use the preset from Klaviyo, but for preference updates, I use JavaScript to check whether a checkbox is checked or not. If it is checked, I send an API request and wait for a response before submitting the form.

View original
Did this topic or the replies in the thread help you find an answer to your question?

6 replies

Christiannoerbjerg
Expert Problem Solver II
Forum|alt.badge.img+12

Hi ​@PatiphonO 

Thank you for posting in the Community!

I think the issue lies in how Klaviyo processes $unsubscribe actions—it treats it as a global opt-out, which may override other preference updates.

Can you confirm that your settings isn’t set to global unsubscription? :-) 

Christian Nørbjerg Enger
Partner & CPO
Web: Segmento.dk
LinkedIn: @christianfromsegmento
Voldbjergvej 22b, 8240 Risskov


Forum|alt.badge.img
  • Author
  • Contributor I
  • 2 replies
  • February 14, 2025
Christiannoerbjerg wrote:

Hi ​@PatiphonO 

Thank you for posting in the Community!

I think the issue lies in how Klaviyo processes $unsubscribe actions—it treats it as a global opt-out, which may override other preference updates.

Can you confirm that your settings isn’t set to global unsubscription? :-) 

Christian Nørbjerg Enger
Partner & CPO
Web: Segmento.dk
LinkedIn: @christianfromsegmento
Voldbjergvej 22b, 8240 Risskov

Where can I find that setting?


Adunni
Active Contributor II
Forum|alt.badge.img+1
  • Active Contributor II
  • 21 replies
  • February 14, 2025

Hi ​@PatiphonO ,

You're on the right path with your Klaviyo-hosted page, but the issue happens because Klaviyo prioritizes unsubscribing over updating custom profile properties. When $unsubscribe is checked, Klaviyo processes it first and doesn't update other preferences like nocatalog.

Solution: Ensure Both Actions Are Processed

To fix this, try these steps:

  1. Use a hidden input field to store nocatalog as a profile property before the form submission.

     

    html

    CopyEdit

    <input type="hidden" name="$fields" value="nocatalog" />

  2. Manually update the property after unsubscribing by adding a Klaviyo API call in JavaScript or using a separate request to ensure nocatalog is updated.

  3. Alternatively, create two separate actions:

    • First, update preferences (nocatalog and others).
    • Then, process the unsubscribe request separately.

Next Steps

If you need help refining your form or setting up the API request, let me know—I’d be happy to guide you through it! 🚀

Cheers,
Adunni


emma.owens
Community Manager
Forum|alt.badge.img+10
  • Community Manager
  • 61 replies
  • February 19, 2025

Hi ​@PatiphonO ! 

Just following up on this - were you able to figure out how to set up the HTML so that it updates both preferences and unsubscribe at the same time? 


Forum|alt.badge.img
  • Author
  • Contributor I
  • 2 replies
  • Answer
  • February 20, 2025
emma.owens wrote:

Hi ​@PatiphonO ! 

Just following up on this - were you able to figure out how to set up the HTML so that it updates both preferences and unsubscribe at the same time? 

Yes, for unsubscribing, I just use the preset from Klaviyo, but for preference updates, I use JavaScript to check whether a checkbox is checked or not. If it is checked, I send an API request and wait for a response before submitting the form.


Vithursan
Contributor I
  • Contributor I
  • 1 reply
  • February 20, 2025

Hi Patiphon,

I understand you're aiming to create a Klaviyo-hosted page that allows users to simultaneously update their email preferences and unsubscribe from marketing communications. The challenge you're encountering—where selecting both the $unsubscribe and nocatalog options results in only the unsubscribe action being processed—is a known behavior in Klaviyo.

Understanding the Behavior:

When a user selects the $unsubscribe option, Klaviyo prioritizes this action, leading to the immediate suppression of the user's profile from all future emails. Consequently, any additional preferences, such as nocatalog, may not be updated as expected because the unsubscribe action takes precedence.

Recommended Solutions:

  1. Separate Unsubscribe and Preference Updates:

    • Unsubscribe Process: If a user selects the unsubscribe option, direct them to a confirmation page informing them that they've been unsubscribed. On this page, provide a link to the preferences page, allowing them to adjust other settings if they wish.
    • Preference Update Process: If a user updates their preferences without selecting unsubscribe, process these changes normally.

    This approach ensures that unsubscribing doesn't interfere with other preference updates.

  2. Modify Form Handling with Conditional Logic:

    • Implement conditional logic in your form's backend processing script:
      • If Unsubscribe is Selected: Process the unsubscribe action first. After confirming the unsubscription, offer the user an option to update other preferences.
      • If Only Preferences are Selected: Process the preference updates as usual.

    This method requires custom scripting to handle the form submission appropriately, ensuring that both actions can be managed without conflict.

Additional Considerations:

  • User Experience: Clearly communicate to users the distinction between unsubscribing and updating preferences. This transparency helps in setting the right expectations.
  • Testing: Before deploying, thoroughly test the form to ensure that all scenarios (unsubscribe only, preference update only, both actions) behave as intended.

For more detailed guidance, you might find Klaviyo's documentation on custom coding consent pages helpful.

I hope this clarifies the issue and provides a viable path forward. If you have further questions or need assistance with the implementation, feel free to ask!

Best regards,

Vithursan