Pular para conteúdo

acceptPolicy()

Visão Geral

O método acceptPolicy() permite registrar programaticamente a aceitação de uma política (Termos de Uso, Política de Privacidade, etc.) por parte de um usuário identificado. Este método é essencial para conformidade com LGPD, que exige consentimento explícito e rastreável.

Para Que Serve?

O acceptPolicy() é utilizado em fluxos onde o usuário precisa aceitar políticas específicas:

  • Registro de Usuários: Aceitar Termos de Uso e Política de Privacidade durante cadastro
  • Checkout de E-commerce: Aceitar políticas antes de finalizar compra
  • Acesso a Recursos: Aceitar políticas específicas antes de usar funcionalidades
  • Conformidade LGPD: Registrar aceitação explícita com auditoria completa
  • Integrações via API: Registrar aceitação de políticas em sistemas backend

Assinatura TypeScript

interface ComplyrAPI {
  /**
   * Registra a aceitação de uma política específica por um usuário identificado
   *
   * @param policyType - Tipo da política ('privacy-policy', 'terms-of-service', etc.)
   * @param userIdentifier - Identificador único do usuário (email recomendado)
   * @returns Promise que resolve quando a aceitação for registrada
   * @throws Error se o script Complyr não estiver carregado ou se houver falha na requisição
   */
  acceptPolicy(policyType: string, userIdentifier: string): Promise<void>;
}

// Acesso via window
declare global {
  interface Window {
    complyr?: ComplyrAPI;
  }
}

Parâmetros

policyType (string, obrigatório)

Tipo da política a ser aceita. Valores suportados:

Valor Descrição Uso Comum
privacy-policy Política de Privacidade Registro, newsletters
terms-of-service Termos de Uso Registro, acesso à plataforma
cookie-policy Política de Cookies Banner de cookies
data-processing Acordo de Processamento de Dados Compartilhamento de dados

Importante: O policyType deve corresponder a uma política publicada no workspace Complyr.

userIdentifier (string, obrigatório)

Identificador único do usuário que está aceitando a política.

Recomendado: Email do usuário

Requisitos: - Deve ser um identificador único e persistente - Será hasheado (SHA-256) antes de ser enviado ao servidor - Não pode ser vazio ou apenas espaços em branco

Exemplos válidos:

'usuario@example.com'        // ✅ Email (recomendado)
'user-uuid-12345'            // ✅ UUID do sistema
'CPF-12345678900'            // ✅ CPF (será hasheado)

Exemplos inválidos:

''                           // ❌ Vazio
'   '                        // ❌ Apenas espaços
null                         // ❌ Null
undefined                    // ❌ Undefined

Valor de Retorno

Tipo: Promise<void>

Resolução: - Promise resolve quando a aceitação for registrada com sucesso no backend - Não retorna nenhum valor (void)

Rejeição: - Promise rejeita se houver erro na requisição - Mensagem de erro disponível em error.message

Exemplo de uso com async/await:

try {
  await window.complyr.acceptPolicy('privacy-policy', 'usuario@example.com');
  console.log('✅ Política aceita com sucesso');
} catch (error) {
  console.error('❌ Erro ao aceitar política:', error.message);
}

Exemplos Práticos

1. Formulário de Registro HTML

Aceitar Termos de Uso e Política de Privacidade durante cadastro:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Registro - Minha Empresa</title>

  <!-- Carregar script Complyr -->
  <script
    src="https://app.complyr.com.br/tag/js"
    data-workspace-id="seu-workspace-id"
    data-complyr-script
    async
    defer>
  </script>
</head>
<body>
  <form id="registration-form">
    <h1>Criar Conta</h1>

    <label for="name">Nome Completo</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" required>

    <label for="password">Senha</label>
    <input type="password" id="password" name="password" required>

    <!-- Checkbox de aceitação -->
    <label>
      <input type="checkbox" id="accept-terms" required>
      Li e aceito os
      <a href="#" onclick="window.complyr.loadPolicy('terms-of-service', '#policy-modal'); return false;">
        Termos de Uso
      </a>
      e a
      <a href="#" onclick="window.complyr.loadPolicy('privacy-policy', '#policy-modal'); return false;">
        Política de Privacidade
      </a>
    </label>

    <button type="submit">Criar Conta</button>
  </form>

  <!-- Container para exibir políticas -->
  <div id="policy-modal"></div>

  <script>
    document.getElementById('registration-form').addEventListener('submit', async function(e) {
      e.preventDefault();

      const email = document.getElementById('email').value;
      const acceptTerms = document.getElementById('accept-terms').checked;

      if (!acceptTerms) {
        alert('Você precisa aceitar os Termos de Uso e a Política de Privacidade');
        return;
      }

      try {
        // Aguardar carregamento do Complyr
        if (!window.complyr) {
          console.error('Script Complyr não carregado');
          return;
        }

        // Registrar aceitação das políticas
        await window.complyr.acceptPolicy('terms-of-service', email);
        await window.complyr.acceptPolicy('privacy-policy', email);

        console.log('✅ Políticas aceitas com sucesso');

        // Enviar formulário para seu backend
        const formData = new FormData(this);
        const response = await fetch('/api/register', {
          method: 'POST',
          body: formData
        });

        if (response.ok) {
          alert('Conta criada com sucesso! Verifique seu email.');
          window.location.href = '/login';
        } else {
          alert('Erro ao criar conta. Tente novamente.');
        }

      } catch (error) {
        console.error('Erro ao processar registro:', error);
        alert('Erro ao registrar políticas. Tente novamente.');
      }
    });

    // Aguardar carregamento do Complyr
    document.addEventListener('complyr:loaded', function() {
      console.log('✅ Complyr carregado e pronto');
    });
  </script>
</body>
</html>

2. Componente React de Registro

Integração com React para formulário de cadastro:

import React, { useState } from 'react';

interface RegistrationFormProps {
  onSuccess?: () => void;
}

export const RegistrationForm: React.FC<RegistrationFormProps> = ({ onSuccess }) => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    acceptTerms: false,
  });

  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError(null);

    // Validar aceitação de termos
    if (!formData.acceptTerms) {
      setError('Você precisa aceitar os Termos de Uso e a Política de Privacidade');
      return;
    }

    setLoading(true);

    try {
      // Verificar se Complyr está carregado
      if (!window.complyr) {
        throw new Error('Sistema de conformidade não disponível. Recarregue a página.');
      }

      // Registrar aceitação das políticas
      await window.complyr.acceptPolicy('terms-of-service', formData.email);
      await window.complyr.acceptPolicy('privacy-policy', formData.email);

      console.log('✅ Políticas aceitas:', {
        email: formData.email,
        policies: ['terms-of-service', 'privacy-policy'],
        timestamp: new Date().toISOString(),
      });

      // Enviar dados do usuário para backend
      const response = await fetch('/api/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: formData.name,
          email: formData.email,
          password: formData.password,
        }),
      });

      if (!response.ok) {
        throw new Error('Erro ao criar conta');
      }

      // Sucesso
      alert('Conta criada com sucesso! Verifique seu email.');
      onSuccess?.();

    } catch (err) {
      console.error('Erro no registro:', err);
      setError(err instanceof Error ? err.message : 'Erro ao processar registro');
    } finally {
      setLoading(false);
    }
  };

  const handleViewPolicy = (policyType: string) => {
    if (window.complyr) {
      window.complyr.loadPolicy(policyType, '#policy-modal');
    }
  };

  return (
    <div className="registration-form">
      <h1>Criar Conta</h1>

      {error && (
        <div className="alert alert-error">
          {error}
        </div>
      )}

      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label htmlFor="name">Nome Completo</label>
          <input
            type="text"
            id="name"
            value={formData.name}
            onChange={(e) => setFormData({ ...formData, name: e.target.value })}
            required
          />
        </div>

        <div className="form-group">
          <label htmlFor="email">Email</label>
          <input
            type="email"
            id="email"
            value={formData.email}
            onChange={(e) => setFormData({ ...formData, email: e.target.value })}
            required
          />
        </div>

        <div className="form-group">
          <label htmlFor="password">Senha</label>
          <input
            type="password"
            id="password"
            value={formData.password}
            onChange={(e) => setFormData({ ...formData, password: e.target.value })}
            required
            minLength={8}
          />
        </div>

        <div className="form-group checkbox">
          <label>
            <input
              type="checkbox"
              checked={formData.acceptTerms}
              onChange={(e) => setFormData({ ...formData, acceptTerms: e.target.checked })}
              required
            />
            Li e aceito os{' '}
            <button
              type="button"
              onClick={() => handleViewPolicy('terms-of-service')}
              className="link-button"
            >
              Termos de Uso
            </button>
            {' '}e a{' '}
            <button
              type="button"
              onClick={() => handleViewPolicy('privacy-policy')}
              className="link-button"
            >
              Política de Privacidade
            </button>
          </label>
        </div>

        <button
          type="submit"
          disabled={loading}
          className="btn btn-primary"
        >
          {loading ? 'Criando conta...' : 'Criar Conta'}
        </button>
      </form>

      {/* Container para exibir políticas */}
      <div id="policy-modal"></div>
    </div>
  );
};

// TypeScript declaration
declare global {
  interface Window {
    complyr?: {
      acceptPolicy(policyType: string, userIdentifier: string): Promise<void>;
      loadPolicy(policyType: string, selector: string): void;
    };
  }
}

3. Hook React Personalizado

Custom hook para facilitar aceitação de políticas em qualquer componente:

import { useState, useCallback } from 'react';

interface UsePolicyAcceptanceOptions {
  onSuccess?: () => void;
  onError?: (error: Error) => void;
}

interface UsePolicyAcceptanceResult {
  acceptPolicy: (policyType: string, userIdentifier: string) => Promise<void>;
  acceptMultiplePolicies: (policyTypes: string[], userIdentifier: string) => Promise<void>;
  loading: boolean;
  error: Error | null;
}

export const usePolicyAcceptance = (
  options: UsePolicyAcceptanceOptions = {}
): UsePolicyAcceptanceResult => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const acceptPolicy = useCallback(async (
    policyType: string,
    userIdentifier: string
  ) => {
    setLoading(true);
    setError(null);

    try {
      if (!window.complyr) {
        throw new Error('Complyr não está disponível');
      }

      await window.complyr.acceptPolicy(policyType, userIdentifier);

      console.log(`✅ Política aceita: ${policyType}`, {
        user: userIdentifier,
        timestamp: new Date().toISOString(),
      });

      options.onSuccess?.();

    } catch (err) {
      const error = err instanceof Error ? err : new Error('Erro desconhecido');
      setError(error);
      options.onError?.(error);
      throw error;
    } finally {
      setLoading(false);
    }
  }, [options]);

  const acceptMultiplePolicies = useCallback(async (
    policyTypes: string[],
    userIdentifier: string
  ) => {
    setLoading(true);
    setError(null);

    try {
      if (!window.complyr) {
        throw new Error('Complyr não está disponível');
      }

      // Aceitar todas as políticas em paralelo
      await Promise.all(
        policyTypes.map(type => window.complyr!.acceptPolicy(type, userIdentifier))
      );

      console.log(`✅ ${policyTypes.length} políticas aceitas`, {
        policies: policyTypes,
        user: userIdentifier,
        timestamp: new Date().toISOString(),
      });

      options.onSuccess?.();

    } catch (err) {
      const error = err instanceof Error ? err : new Error('Erro desconhecido');
      setError(error);
      options.onError?.(error);
      throw error;
    } finally {
      setLoading(false);
    }
  }, [options]);

  return {
    acceptPolicy,
    acceptMultiplePolicies,
    loading,
    error,
  };
};

// Exemplo de uso do hook
export const RegistrationFormWithHook: React.FC = () => {
  const [email, setEmail] = useState('');
  const [acceptTerms, setAcceptTerms] = useState(false);

  const { acceptMultiplePolicies, loading, error } = usePolicyAcceptance({
    onSuccess: () => {
      alert('Políticas aceitas! Conta criada com sucesso.');
      window.location.href = '/dashboard';
    },
    onError: (error) => {
      console.error('Erro ao aceitar políticas:', error);
    },
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    if (!acceptTerms) {
      alert('Você precisa aceitar as políticas');
      return;
    }

    try {
      await acceptMultiplePolicies(
        ['terms-of-service', 'privacy-policy'],
        email
      );
    } catch (err) {
      // Erro já tratado pelo hook
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />

      <label>
        <input
          type="checkbox"
          checked={acceptTerms}
          onChange={(e) => setAcceptTerms(e.target.checked)}
        />
        Aceito as políticas
      </label>

      {error && <p className="error">{error.message}</p>}

      <button type="submit" disabled={loading}>
        {loading ? 'Processando...' : 'Criar Conta'}
      </button>
    </form>
  );
};

4. Vue.js Composable

Composable para Vue 3 com Composition API:

import { ref } from 'vue';

interface PolicyAcceptanceOptions {
  onSuccess?: () => void;
  onError?: (error: Error) => void;
}

export function usePolicyAcceptance(options: PolicyAcceptanceOptions = {}) {
  const loading = ref(false);
  const error = ref<Error | null>(null);

  const acceptPolicy = async (policyType: string, userIdentifier: string) => {
    loading.value = true;
    error.value = null;

    try {
      if (!window.complyr) {
        throw new Error('Complyr não está disponível');
      }

      await window.complyr.acceptPolicy(policyType, userIdentifier);

      console.log(`✅ Política aceita: ${policyType}`, {
        user: userIdentifier,
        timestamp: new Date().toISOString(),
      });

      options.onSuccess?.();

    } catch (err) {
      const errorObj = err instanceof Error ? err : new Error('Erro desconhecido');
      error.value = errorObj;
      options.onError?.(errorObj);
      throw errorObj;
    } finally {
      loading.value = false;
    }
  };

  const acceptMultiplePolicies = async (
    policyTypes: string[],
    userIdentifier: string
  ) => {
    loading.value = true;
    error.value = null;

    try {
      if (!window.complyr) {
        throw new Error('Complyr não está disponível');
      }

      await Promise.all(
        policyTypes.map(type => window.complyr!.acceptPolicy(type, userIdentifier))
      );

      console.log(`✅ ${policyTypes.length} políticas aceitas`);
      options.onSuccess?.();

    } catch (err) {
      const errorObj = err instanceof Error ? err : new Error('Erro desconhecido');
      error.value = errorObj;
      options.onError?.(errorObj);
      throw errorObj;
    } finally {
      loading.value = false;
    }
  };

  return {
    acceptPolicy,
    acceptMultiplePolicies,
    loading,
    error,
  };
}

Exemplo de uso no componente Vue:

<template>
  <form @submit.prevent="handleSubmit">
    <h1>Criar Conta</h1>

    <div v-if="error" class="alert alert-error">
      {{ error.message }}
    </div>

    <div class="form-group">
      <label for="email">Email</label>
      <input
        type="email"
        id="email"
        v-model="formData.email"
        required
      />
    </div>

    <div class="form-group">
      <label>
        <input
          type="checkbox"
          v-model="formData.acceptTerms"
          required
        />
        Li e aceito as políticas
      </label>
    </div>

    <button type="submit" :disabled="loading">
      {{ loading ? 'Processando...' : 'Criar Conta' }}
    </button>
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue';
import { usePolicyAcceptance } from '@/composables/usePolicyAcceptance';

const formData = reactive({
  email: '',
  acceptTerms: false,
});

const { acceptMultiplePolicies, loading, error } = usePolicyAcceptance({
  onSuccess: () => {
    alert('Conta criada com sucesso!');
    window.location.href = '/dashboard';
  },
});

const handleSubmit = async () => {
  if (!formData.acceptTerms) {
    alert('Você precisa aceitar as políticas');
    return;
  }

  try {
    await acceptMultiplePolicies(
      ['terms-of-service', 'privacy-policy'],
      formData.email
    );
  } catch (err) {
    console.error('Erro:', err);
  }
};
</script>

5. E-commerce: Checkout com Aceitação de Políticas

Aceitar políticas durante finalização de compra:

// Checkout page
document.addEventListener('DOMContentLoaded', function() {
  const checkoutForm = document.getElementById('checkout-form');

  checkoutForm.addEventListener('submit', async function(e) {
    e.preventDefault();

    const customerEmail = document.getElementById('customer-email').value;
    const acceptDataProcessing = document.getElementById('accept-data-processing').checked;

    if (!acceptDataProcessing) {
      alert('Você precisa aceitar o Acordo de Processamento de Dados para continuar');
      return;
    }

    try {
      // Registrar aceitação do acordo de processamento de dados
      if (window.complyr) {
        await window.complyr.acceptPolicy('data-processing', customerEmail);
        console.log('✅ Acordo de processamento aceito');
      }

      // Processar pagamento
      const paymentData = {
        email: customerEmail,
        amount: calculateTotal(),
        items: getCartItems(),
      };

      const response = await fetch('/api/checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(paymentData),
      });

      if (response.ok) {
        window.location.href = '/order-confirmation';
      } else {
        alert('Erro ao processar pedido');
      }

    } catch (error) {
      console.error('Erro no checkout:', error);
      alert('Erro ao processar pedido. Tente novamente.');
    }
  });
});

6. WordPress: Plugin de Registro

Integração com WordPress para aceitar políticas no registro:

<?php
/**
 * Plugin Name: Complyr Policy Acceptance
 * Description: Integra aceitação de políticas Complyr no registro do WordPress
 * Version: 1.0.0
 */

// Adicionar campos ao formulário de registro
add_action('register_form', 'complyr_add_registration_fields');
function complyr_add_registration_fields() {
    ?>
    <p>
        <label>
            <input type="checkbox" name="accept_policies" required />
            <?php _e('Li e aceito os'); ?>
            <a href="#" onclick="event.preventDefault(); window.complyr.loadPolicy('terms-of-service', '#policy-container');">
                <?php _e('Termos de Uso'); ?>
            </a>
            <?php _e('e a'); ?>
            <a href="#" onclick="event.preventDefault(); window.complyr.loadPolicy('privacy-policy', '#policy-container');">
                <?php _e('Política de Privacidade'); ?>
            </a>
        </label>
    </p>

    <div id="policy-container"></div>
    <?php
}

// Validar aceitação antes de criar usuário
add_filter('registration_errors', 'complyr_validate_registration', 10, 3);
function complyr_validate_registration($errors, $sanitized_user_login, $user_email) {
    if (!isset($_POST['accept_policies'])) {
        $errors->add('policy_error', __('Você precisa aceitar as políticas para continuar'));
    }

    return $errors;
}

// Registrar aceitação após criar usuário
add_action('user_register', 'complyr_register_policy_acceptance');
function complyr_register_policy_acceptance($user_id) {
    $user = get_userdata($user_id);
    $workspace_id = get_option('complyr_workspace_id');

    if (!$workspace_id || !$user) {
        return;
    }

    // Enfileirar JavaScript para registrar aceitação
    add_action('wp_footer', function() use ($user) {
        ?>
        <script>
        document.addEventListener('complyr:loaded', async function() {
            try {
                await window.complyr.acceptPolicy('terms-of-service', '<?php echo esc_js($user->user_email); ?>');
                await window.complyr.acceptPolicy('privacy-policy', '<?php echo esc_js($user->user_email); ?>');
                console.log('✅ Políticas registradas para novo usuário');
            } catch (error) {
                console.error('Erro ao registrar políticas:', error);
            }
        });
        </script>
        <?php
    });
}

// Adicionar script Complyr ao header
add_action('wp_head', 'complyr_add_script');
function complyr_add_script() {
    $workspace_id = get_option('complyr_workspace_id');

    if (!$workspace_id) {
        return;
    }
    ?>
    <script
        src="https://app.complyr.com.br/tag/js"
        data-workspace-id="<?php echo esc_attr($workspace_id); ?>"
        data-complyr-script
        async
        defer>
    </script>
    <?php
}

7. Next.js API Route

Aceitar políticas via rota de API server-side:

// pages/api/register.ts
import type { NextApiRequest, NextApiResponse } from 'next';

interface RegisterRequest {
  name: string;
  email: string;
  password: string;
  acceptPolicies: boolean;
}

interface RegisterResponse {
  success: boolean;
  message: string;
  userId?: string;
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<RegisterResponse>
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ success: false, message: 'Method not allowed' });
  }

  const { name, email, password, acceptPolicies }: RegisterRequest = req.body;

  // Validar dados
  if (!acceptPolicies) {
    return res.status(400).json({
      success: false,
      message: 'Você precisa aceitar as políticas',
    });
  }

  try {
    // 1. Criar usuário no banco de dados
    const user = await createUser({ name, email, password });

    // 2. Registrar aceitação de políticas via Complyr API
    const workspaceId = process.env.COMPLYR_WORKSPACE_ID!;
    const apiUrl = process.env.COMPLYR_API_URL || 'https://app.complyr.com.br/api';

    // Aceitar múltiplas políticas em paralelo
    await Promise.all([
      fetch(`${apiUrl}/policy-acceptances`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Workspace-ID': workspaceId,
        },
        body: JSON.stringify({
          policyType: 'terms-of-service',
          userEmail: email,
        }),
      }),
      fetch(`${apiUrl}/policy-acceptances`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Workspace-ID': workspaceId,
        },
        body: JSON.stringify({
          policyType: 'privacy-policy',
          userEmail: email,
        }),
      }),
    ]);

    console.log(`✅ Políticas registradas para ${email}`);

    // 3. Enviar email de boas-vindas
    await sendWelcomeEmail(email, name);

    return res.status(201).json({
      success: true,
      message: 'Conta criada com sucesso',
      userId: user.id,
    });

  } catch (error) {
    console.error('Erro no registro:', error);
    return res.status(500).json({
      success: false,
      message: 'Erro ao criar conta',
    });
  }
}

// Funções auxiliares
async function createUser(data: { name: string; email: string; password: string }) {
  // Implementação de criação de usuário
  // ...
  return { id: 'user-123' };
}

async function sendWelcomeEmail(email: string, name: string) {
  // Implementação de envio de email
  // ...
}

Componente Next.js correspondente:

// components/RegistrationForm.tsx
'use client';

import { useState } from 'react';

export default function RegistrationForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    acceptPolicies: false,
  });

  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    try {
      // Validar frontend
      if (!formData.acceptPolicies) {
        alert('Você precisa aceitar as políticas');
        return;
      }

      // Enviar para API route
      const response = await fetch('/api/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData),
      });

      const data = await response.json();

      if (data.success) {
        alert('Conta criada com sucesso!');
        window.location.href = '/login';
      } else {
        alert(data.message);
      }

    } catch (error) {
      console.error('Erro:', error);
      alert('Erro ao criar conta');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Campos do formulário */}
      <input
        type="text"
        placeholder="Nome"
        value={formData.name}
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        required
      />

      <input
        type="email"
        placeholder="Email"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        required
      />

      <input
        type="password"
        placeholder="Senha"
        value={formData.password}
        onChange={(e) => setFormData({ ...formData, password: e.target.value })}
        required
      />

      <label>
        <input
          type="checkbox"
          checked={formData.acceptPolicies}
          onChange={(e) => setFormData({ ...formData, acceptPolicies: e.target.checked })}
          required
        />
        Aceito as políticas
      </label>

      <button type="submit" disabled={loading}>
        {loading ? 'Criando...' : 'Criar Conta'}
      </button>
    </form>
  );
}

Fluxo de Execução

sequenceDiagram
    participant User as Usuário
    participant App as Aplicação
    participant Complyr as window.complyr
    participant API as Complyr API
    participant DB as Banco de Dados

    User->>App: Clica em "Criar Conta"
    App->>App: Valida campos do formulário
    App->>App: Verifica acceptTerms === true

    App->>Complyr: acceptPolicy('terms-of-service', email)
    Complyr->>Complyr: Valida parâmetros
    Complyr->>Complyr: Hasheia email (SHA-256)
    Complyr->>API: POST /policy-acceptances
    Note over API: { policyType, userEmail (hashed), workspaceId }
    API->>DB: Registra aceitação
    DB-->>API: Aceitação salva
    API-->>Complyr: 200 OK
    Complyr-->>App: Promise resolved

    App->>Complyr: acceptPolicy('privacy-policy', email)
    Complyr->>API: POST /policy-acceptances
    API->>DB: Registra aceitação
    DB-->>API: Aceitação salva
    API-->>Complyr: 200 OK
    Complyr-->>App: Promise resolved

    App->>App: Cria usuário no sistema
    App->>User: Exibe "Conta criada com sucesso"
    App->>App: Redireciona para /dashboard

Conformidade LGPD

Consentimento Explícito (Art. 7º, I)

O método acceptPolicy() implementa conformidade com o artigo 7º, inciso I da LGPD, que exige consentimento explícito do titular dos dados:

Art. 7º O tratamento de dados pessoais somente poderá ser realizado nas seguintes hipóteses:

I - mediante o fornecimento de consentimento pelo titular;

Como o Complyr implementa:

  1. Aceitação Ativa: Usuário deve marcar checkbox explicitamente (não pode ser pré-marcada)
  2. Rastreabilidade: Registro inclui timestamp, IP, user-agent e identificador do usuário
  3. Granularidade: Cada política é aceita individualmente, permitindo controle por finalidade
  4. Revogabilidade: Usuário pode revogar consentimento a qualquer momento via revokeConsent()

Registro de Aceitação (Auditoria)

Toda chamada a acceptPolicy() gera registro de auditoria no backend:

{
  "id": "uuid-123",
  "workspaceId": "workspace-456",
  "policyType": "privacy-policy",
  "userEmail": "hash-sha256-do-email",
  "acceptedAt": "2025-10-22T14:30:00Z",
  "ipAddress": "192.168.1.100",
  "userAgent": "Mozilla/5.0...",
  "consentVersion": "1.0.0"
}

Informações rastreadas: - ✅ Quem aceitou (identificador hasheado) - ✅ O que aceitou (tipo de política) - ✅ Quando aceitou (timestamp UTC) - ✅ De onde aceitou (endereço IP) - ✅ Como aceitou (navegador, dispositivo) - ✅ Versão da política aceita

Finalidade Específica

Cada política aceita deve ter finalidade clara e específica:

Política Finalidade Exemplo de Uso
terms-of-service Uso da plataforma Acesso aos recursos do sistema
privacy-policy Tratamento de dados pessoais Coleta, armazenamento, processamento
cookie-policy Cookies e rastreamento Analytics, personalização, publicidade
data-processing Compartilhamento com terceiros Processadores de pagamento, email

Tempo de Retenção

As aceitações de políticas são mantidas pelo tempo necessário para comprovar conformidade com LGPD:

  • Durante relacionamento ativo: Enquanto usuário usar o serviço
  • Após encerramento: 5 anos para fins de defesa legal (Art. 16, I)
  • Exclusão a pedido: Usuário pode solicitar exclusão via DSAR (Art. 18, VI)

Tratamento de Erros

Erros Comuns

1. Script Complyr não carregado:

try {
  if (!window.complyr) {
    throw new Error('Sistema de conformidade não disponível');
  }

  await window.complyr.acceptPolicy('privacy-policy', email);
} catch (error) {
  console.error('Erro:', error.message);
  // Fallback: salvar aceitação localmente e sincronizar depois
  localStorage.setItem('pending_policy_acceptance', JSON.stringify({
    policyType: 'privacy-policy',
    email: email,
    timestamp: new Date().toISOString(),
  }));
}

2. Política não encontrada:

try {
  await window.complyr.acceptPolicy('invalid-policy', email);
} catch (error) {
  if (error.message.includes('not found')) {
    console.error('Política não existe no workspace');
    alert('Erro de configuração. Contate o suporte.');
  }
}

3. Erro de rede:

try {
  await window.complyr.acceptPolicy('privacy-policy', email);
} catch (error) {
  if (error.message.includes('network') || error.message.includes('timeout')) {
    console.error('Erro de conexão:', error);

    // Tentar novamente após 3 segundos
    setTimeout(async () => {
      try {
        await window.complyr.acceptPolicy('privacy-policy', email);
        console.log('✅ Política aceita na segunda tentativa');
      } catch (retryError) {
        console.error('Falha na segunda tentativa:', retryError);
      }
    }, 3000);
  }
}

4. Email inválido:

const email = userInput.trim();

if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
  alert('Email inválido');
  return;
}

try {
  await window.complyr.acceptPolicy('privacy-policy', email);
} catch (error) {
  console.error('Erro ao aceitar política:', error);
}

Estratégia de Retry com Exponential Backoff

Para aplicações críticas, implemente retry automático:

async function acceptPolicyWithRetry(policyType, email, maxRetries = 3) {
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await window.complyr.acceptPolicy(policyType, email);
      console.log(`✅ Política aceita (tentativa ${attempt})`);
      return; // Sucesso

    } catch (error) {
      lastError = error;
      console.warn(`⚠️ Tentativa ${attempt} falhou:`, error.message);

      if (attempt < maxRetries) {
        // Exponential backoff: 1s, 2s, 4s
        const delay = Math.pow(2, attempt - 1) * 1000;
        console.log(`Aguardando ${delay}ms antes de tentar novamente...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  // Todas as tentativas falharam
  throw new Error(`Falha após ${maxRetries} tentativas: ${lastError.message}`);
}

// Uso
try {
  await acceptPolicyWithRetry('privacy-policy', 'usuario@example.com');
} catch (error) {
  console.error('❌ Não foi possível registrar aceitação:', error);
  // Notificar usuário e/ou salvar localmente
}

Verificação de Debug

1. Verificar se política foi aceita

Consulte o localStorage para verificar aceitações locais:

// Verificar consentimento armazenado
const consent = localStorage.getItem('complyr_consent');
if (consent) {
  const consentData = JSON.parse(consent);
  console.log('Consentimento armazenado:', consentData);
}

// Verificar via API (requer autenticação)
const response = await fetch(`https://app.complyr.com.br/api/policy-acceptances?email=${email}`);
const acceptances = await response.json();
console.log('Políticas aceitas:', acceptances);

2. Verificar chamadas de rede

Abra DevTools → Network → XHR/Fetch e procure por:

  • Endpoint: POST https://app.complyr.com.br/api/policy-acceptances
  • Status: 200 OK (sucesso)
  • Payload:
    {
      "policyType": "privacy-policy",
      "userEmail": "hash-sha256...",
      "workspaceId": "workspace-id"
    }
    

3. Console Logs

Ative logs detalhados:

// Antes de chamar acceptPolicy
console.log('🔵 Iniciando aceitação de política', {
  policyType: 'privacy-policy',
  email: email,
  timestamp: new Date().toISOString(),
});

await window.complyr.acceptPolicy('privacy-policy', email);

console.log('✅ Política aceita com sucesso');

4. Auditoria Backend

Consulte o painel Complyr para ver auditoria completa:

  1. Acesse https://app.complyr.com.br/dashboard
  2. Vá em Auditoria → Policy Acceptances
  3. Filtre por email do usuário
  4. Verifique timestamp, IP, user-agent

Melhores Práticas

✅ DOs (Faça)

  1. Sempre validar checkbox antes de chamar acceptPolicy()

    if (!acceptTermsCheckbox.checked) {
      alert('Você precisa aceitar as políticas');
      return;
    }
    

  2. Usar try/catch para tratamento de erros

    try {
      await window.complyr.acceptPolicy('privacy-policy', email);
    } catch (error) {
      console.error('Erro:', error);
    }
    

  3. Aceitar políticas ANTES de criar o usuário no backend

    // ✅ Ordem correta
    await window.complyr.acceptPolicy('terms-of-service', email);
    await createUser(email, password);
    

  4. Usar email como identificador (recomendado)

    await window.complyr.acceptPolicy('privacy-policy', user.email);
    

  5. Aceitar múltiplas políticas em paralelo

    await Promise.all([
      window.complyr.acceptPolicy('terms-of-service', email),
      window.complyr.acceptPolicy('privacy-policy', email),
    ]);
    

  6. Fornecer feedback visual ao usuário

    setLoading(true);
    await window.complyr.acceptPolicy('privacy-policy', email);
    setLoading(false);
    alert('Políticas aceitas com sucesso!');
    

  7. Logs para debug e auditoria

    console.log('✅ Política aceita:', {
      policyType,
      email,
      timestamp: new Date().toISOString(),
    });
    

  8. Exibir políticas antes da aceitação

    // Permitir usuário ler antes de aceitar
    window.complyr.loadPolicy('privacy-policy', '#modal');
    

❌ DON'Ts (Não Faça)

  1. Não aceitar políticas sem consentimento explícito

    // ❌ ERRADO - aceitar automaticamente
    window.addEventListener('load', () => {
      window.complyr.acceptPolicy('privacy-policy', 'user@example.com');
    });
    

  2. Não usar identificadores genéricos

    // ❌ ERRADO
    await window.complyr.acceptPolicy('privacy-policy', 'user123');
    await window.complyr.acceptPolicy('privacy-policy', 'anonymous');
    

  3. Não ignorar erros silenciosamente

    // ❌ ERRADO
    window.complyr.acceptPolicy('privacy-policy', email).catch(() => {});
    

  4. Não aceitar políticas inexistentes

    // ❌ ERRADO - verificar se política existe no workspace
    await window.complyr.acceptPolicy('non-existent-policy', email);
    

  5. Não chamar sem verificar se Complyr está carregado

    // ❌ ERRADO
    window.complyr.acceptPolicy('privacy-policy', email); // Pode dar erro
    
    // ✅ CORRETO
    if (window.complyr) {
      await window.complyr.acceptPolicy('privacy-policy', email);
    }
    

  6. Não usar checkboxes pré-marcadas

    <!-- ❌ ERRADO -->
    <input type="checkbox" checked />
    
    <!-- ✅ CORRETO -->
    <input type="checkbox" />
    

  7. Não aceitar políticas após erro no registro

    // ❌ ERRADO - ordem invertida
    await createUser(email);
    await window.complyr.acceptPolicy('privacy-policy', email);
    
    // ✅ CORRETO
    await window.complyr.acceptPolicy('privacy-policy', email);
    await createUser(email);
    

Perguntas Frequentes (FAQ)

1. Quando devo usar acceptPolicy() vs loadPolicy()?

Use acceptPolicy() quando: - Usuário já aceitou a política (marcou checkbox) - Você quer registrar a aceitação no backend - É parte de um fluxo de cadastro ou checkout

Use loadPolicy() quando: - Usuário quer ler a política antes de decidir - Você quer exibir o conteúdo da política em uma modal ou página

Exemplo combinado:

// 1. Usuário clica "Ler Política"
btnReadPolicy.onclick = () => {
  window.complyr.loadPolicy('privacy-policy', '#modal');
};

// 2. Usuário marca checkbox e submete formulário
form.onsubmit = async (e) => {
  e.preventDefault();
  if (checkbox.checked) {
    await window.complyr.acceptPolicy('privacy-policy', email);
    // Prosseguir com registro
  }
};

2. Posso aceitar múltiplas políticas de uma vez?

Sim! Use Promise.all() para aceitar múltiplas políticas em paralelo:

await Promise.all([
  window.complyr.acceptPolicy('terms-of-service', email),
  window.complyr.acceptPolicy('privacy-policy', email),
  window.complyr.acceptPolicy('cookie-policy', email),
]);

console.log('✅ Todas as 3 políticas aceitas');

Benefícios: - Mais rápido (execução paralela) - Atomicidade: se uma falhar, todas falham - Código mais limpo

3. O que acontece se chamar acceptPolicy() duas vezes para a mesma política?

O sistema registrará duas aceitações separadas. Não há problema, mas é redundante.

Comportamento: - Primeira chamada: Cria registro de aceitação - Segunda chamada: Cria novo registro de aceitação

Recomendação: Evite chamadas duplicadas usando flags:

let policiesAccepted = false;

async function acceptPoliciesOnce(email) {
  if (policiesAccepted) {
    console.log('Políticas já foram aceitas');
    return;
  }

  await window.complyr.acceptPolicy('privacy-policy', email);
  policiesAccepted = true;
}

4. Preciso identificar o usuário com identify() antes de acceptPolicy()?

Não é obrigatório, mas é altamente recomendado para rastreamento mais preciso:

// ✅ Recomendado: Identificar antes de aceitar
window.complyr.identify('email', 'usuario@example.com');
await window.complyr.acceptPolicy('privacy-policy', 'usuario@example.com');

// ✅ Também funciona sem identify()
await window.complyr.acceptPolicy('privacy-policy', 'usuario@example.com');

Benefícios de usar identify() antes: - Melhor rastreamento cross-device - Analytics mais precisos (GTM, Facebook Pixel) - Consentimento vinculado corretamente ao usuário

5. Posso usar acceptPolicy() para aceitar consentimento de cookies?

Não. Para consentimento de cookies (Analytics, Marketing, etc.), use o banner nativo do Complyr ou chame métodos específicos de consentimento.

acceptPolicy() é para: - ✅ Termos de Uso - ✅ Política de Privacidade - ✅ Política de Cookies (documento) - ✅ Acordo de Processamento de Dados

Para consentimento de cookies e finalidades, use:

// Banner nativo (recomendado)
// O usuário aceita via interface gráfica

// Ou aceitar programaticamente via API
await fetch('https://app.complyr.com.br/api/consents', {
  method: 'POST',
  body: JSON.stringify({
    workspaceId: 'workspace-id',
    purposes: [
      { purposeId: 'analytics', granted: true },
      { purposeId: 'marketing', granted: true },
    ],
  }),
});

6. Como verificar se uma política já foi aceita por um usuário?

Consulte a API de aceitações de políticas:

async function checkPolicyAcceptance(email, policyType) {
  try {
    const response = await fetch(
      `https://app.complyr.com.br/api/policy-acceptances?` +
      `email=${encodeURIComponent(email)}&` +
      `policyType=${encodeURIComponent(policyType)}`
    );

    if (!response.ok) {
      throw new Error('Erro ao verificar aceitação');
    }

    const acceptances = await response.json();

    if (acceptances.length > 0) {
      console.log(`✅ Política "${policyType}" já foi aceita em:`, acceptances[0].acceptedAt);
      return true;
    } else {
      console.log(`❌ Política "${policyType}" ainda não foi aceita`);
      return false;
    }

  } catch (error) {
    console.error('Erro ao verificar:', error);
    return false;
  }
}

// Uso
const hasAccepted = await checkPolicyAcceptance('user@example.com', 'privacy-policy');
if (!hasAccepted) {
  // Mostrar formulário de aceitação
}

7. O email é hasheado antes de ser enviado ao servidor?

Sim! Por segurança e conformidade com LGPD, o email (ou qualquer identificador) é automaticamente hasheado com SHA-256 antes de ser enviado ao servidor.

Processo: 1. Você chama: acceptPolicy('privacy-policy', 'usuario@example.com') 2. Complyr hasheia: SHA-256('usuario@example.com')'5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8' 3. Envia ao servidor: { userEmail: '5e884898...' }

Benefícios: - Proteção de dados pessoais em trânsito - Conformidade com Art. 46 da LGPD (segurança) - Impossibilidade de engenharia reversa

8. Posso usar acceptPolicy() em aplicações mobile (React Native, Flutter)?

Não diretamente. O método acceptPolicy() é parte da API JavaScript do navegador (window.complyr).

Para aplicações mobile, use a API REST:

// React Native / Flutter
async function acceptPolicy(policyType, userEmail) {
  const response = await fetch('https://app.complyr.com.br/api/policy-acceptances', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Workspace-ID': 'seu-workspace-id',
    },
    body: JSON.stringify({
      policyType: policyType,
      userEmail: userEmail, // Será hasheado pelo servidor
    }),
  });

  if (!response.ok) {
    throw new Error('Erro ao aceitar política');
  }

  return await response.json();
}

// Uso
await acceptPolicy('privacy-policy', 'usuario@example.com');

9. Qual a diferença entre aceitar uma política e dar consentimento de cookies?

Aspecto Aceitar Política Consentimento de Cookies
Método acceptPolicy() Banner nativo Complyr
O que registra Aceitação de documento legal (Termos, Privacidade) Permissão para finalidades (Analytics, Marketing)
Quando usar Cadastro, login, checkout Primeira visita ao site
Granularidade Por política Por finalidade (5 categorias)
Obrigatório? Depende do serviço Sim (LGPD Art. 7º, I)
Revogável? Via DSAR Via revokeConsent() ou banner

Exemplo de fluxo completo:

// 1. Primeira visita: Consentimento de cookies (banner)
// → Usuário aceita Analytics e Marketing

// 2. Registro: Aceitar políticas
document.getElementById('signup-form').onsubmit = async (e) => {
  e.preventDefault();

  const email = document.getElementById('email').value;

  // Aceitar Termos e Privacidade
  await window.complyr.acceptPolicy('terms-of-service', email);
  await window.complyr.acceptPolicy('privacy-policy', email);

  // Criar conta
  await createUser(email);
};

10. Há limite de chamadas para acceptPolicy()?

Sim, existe rate limiting para prevenir abuso:

  • Limite padrão: 20 requisições por minuto por workspace
  • Limite por IP: 100 requisições por minuto

Se exceder o limite: - HTTP Status: 429 Too Many Requests - Mensagem: "Rate limit exceeded. Try again later." - Headers:

X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1698012345

Recomendações: - Não chame acceptPolicy() em loops ou intervalos - Aceite políticas apenas quando usuário explicitamente aceitar - Use cache para evitar chamadas duplicadas

Suporte

Recursos Adicionais

Contato

Métodos Relacionados