Pular para o conteúdo principal

White Labelling

Este documento detalha como personalizar completamente a aparência do n8n embarcado para sua marca, incluindo cores, logos, fontes, layout, domínio customizado, e integração visual perfeita com sua aplicação principal, criando uma experiência unificada e profissional para seus usuários.

Configuração Básica

Variáveis de Tema

N8N_THEME_FONT_FAMILY="Inter, -apple-system, BlinkMacSystemFont, sans-serif"
N8N_THEME_FONT_SIZE_BASE=14px
N8N_THEME_BORDER_RADIUS=8px
N8N_THEME_SHADOW=0 4px 6px -1px rgba(0, 0, 0, 0.1)

Configuração via Docker

# docker-compose.yml
version: '3.8'
services:
  n8n:
    image: n8nio/n8n
    environment:
      - N8N_THEME_FONT_FAMILY=Inter, sans-serif
      - N8N_THEME_FONT_SIZE_BASE=14px
      - N8N_THEME_BORDER_RADIUS=8px
    volumes:
      - ./custom-theme:/app/custom-theme
    ports:
      - "5678:5678"

Esquemas de Cores

Tema Escuro

/* dark-theme.css */
:root {
  --n8n-background-color: #1f2937;
  --n8n-surface-color: #374151;
  --n8n-text-color: #f9fafb;
  --n8n-border-color: #4b5563;
  --n8n-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}

/* Aplicar tema escuro */
body[data-theme="dark"] {
  background-color: var(--n8n-background-color);
  color: var(--n8n-text-color);
}

body[data-theme="dark"] .n8n-card {
  background-color: var(--n8n-surface-color);
  border-color: var(--n8n-border-color);
  box-shadow: var(--n8n-shadow);
}

Tema Corporativo

/* corporate-theme.css */
:root {
  --n8n-primary-color: #1e40af;
  --n8n-secondary-color: #059669;
  --n8n-accent-color: #dc2626;
  --n8n-background-color: #ffffff;
  --n8n-surface-color: #f8fafc;
  --n8n-text-color: #1e293b;
  --n8n-border-color: #e2e8f0;
  --n8n-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}

/* Estilo corporativo */
.n8n-header {
  background: var(--n8n-primary-color);
  color: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.n8n-button-primary {
  background: var(--n8n-primary-color);
  border: none;
  border-radius: 6px;
  padding: 12px 24px;
  font-weight: 600;
  transition: all 0.2s ease;
}

.n8n-button-primary:hover {
  background: #1d4ed8;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(30, 64, 175, 0.3);
}

Branding e Logos

N8N_THEME_LOGO_ALT="Sua Empresa - Automação"
/* Logo principal */
.n8n-header-logo {
  background-image: url('https://sua-empresa.com/logo.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 150px;
  height: 40px;
}

/* Logo responsivo */
@media (max-width: 768px) {
  .n8n-header-logo {
    width: 120px;
    height: 32px;
  }
}

/* Logo para tema escuro */
body[data-theme="dark"] .n8n-header-logo {
  background-image: url('https://sua-empresa.com/logo-white.png');
}

Textos e Marca

Configuração de Textos Customizados

N8N_THEME_APP_NAME="Sua Empresa - Automação"
N8N_THEME_APP_DESCRIPTION="Plataforma de automação empresarial"
N8N_THEME_FOOTER_TEXT="© 2024 Sua Empresa. Todos os direitos reservados."
N8N_THEME_HELP_TEXT="Precisa de ajuda? Entre em contato com nosso suporte."

CSS para Textos Customizados

/* custom-text.css */
.n8n-app-name {
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: 24px;
  color: var(--n8n-primary-color);
}

.n8n-app-description {
  font-size: 14px;
  color: var(--n8n-text-secondary);
  margin-top: 4px;
}

.n8n-footer {
  background-color: var(--n8n-surface-color);
  border-top: 1px solid var(--n8n-border-color);
  padding: 16px 24px;
  text-align: center;
  font-size: 12px;
  color: var(--n8n-text-secondary);
}

CSS Customizado

Estilos Avançados

Layout Customizado

/* custom-layout.css */
/* Header customizado */
.n8n-header {
  background: linear-gradient(135deg, var(--n8n-primary-color), var(--n8n-secondary-color));
  padding: 16px 24px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* Sidebar customizada */
.n8n-sidebar {
  background-color: var(--n8n-surface-color);
  border-right: 1px solid var(--n8n-border-color);
  width: 280px;
  transition: width 0.3s ease;
}

.n8n-sidebar.collapsed {
  width: 60px;
}

/* Cards customizados */
.n8n-card {
  background: var(--n8n-surface-color);
  border: 1px solid var(--n8n-border-color);
  border-radius: var(--n8n-border-radius);
  box-shadow: var(--n8n-shadow);
  transition: all 0.2s ease;
}

.n8n-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}

/* Botões customizados */
.n8n-button {
  border-radius: var(--n8n-border-radius);
  font-weight: 600;
  transition: all 0.2s ease;
  border: none;
  cursor: pointer;
}

.n8n-button-primary {
  background: var(--n8n-primary-color);
  color: white;
}

.n8n-button-primary:hover {
  background: var(--n8n-secondary-color);
  color: white;
}

.n8n-button-secondary:hover {
  background: #059669;
  transform: translateY(-1px);
}

Componentes Específicos

/* custom-components.css */
/* Nodes customizados */
.n8n-node {
  border-radius: 8px;
  border: 2px solid var(--n8n-border-color);
  background: var(--n8n-surface-color);
  transition: all 0.2s ease;
}

.n8n-node:hover {
  border-color: var(--n8n-primary-color);
  box-shadow: 0 4px 8px rgba(234, 75, 113, 0.2);
}

.n8n-node.selected {
  border-color: var(--n8n-primary-color);
  box-shadow: 0 0 0 3px rgba(234, 75, 113, 0.3);
}

/* Canvas customizado */
.n8n-canvas {
  background-image: 
    linear-gradient(rgba(0,0,0,.1) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,0,0,.1) 1px, transparent 1px);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}

/* Toolbar customizada */
.n8n-toolbar {
  background: var(--n8n-surface-color);
  border-bottom: 1px solid var(--n8n-border-color);
  padding: 12px 24px;
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Status indicators */
.n8n-status-success {
  color: var(--n8n-secondary-color);
  background: rgba(16, 185, 129, 0.1);
  border: 1px solid rgba(16, 185, 129, 0.2);
  border-radius: 4px;
  padding: 4px 8px;
  font-size: 12px;
  font-weight: 600;
}

.n8n-status-error {
  color: var(--n8n-accent-color);
  background: rgba(220, 38, 38, 0.1);
  border: 1px solid rgba(220, 38, 38, 0.2);
  border-radius: 4px;
  padding: 4px 8px;
  font-size: 12px;
  font-weight: 600;
}

Responsividade

/* responsive.css */
/* Mobile (até 768px) */
@media (max-width: 768px) {
  .n8n-header {
    padding: 12px 16px;
  }

  .n8n-sidebar {
    position: fixed;
    left: -280px;
    z-index: 1000;
    transition: left 0.3s ease;
  }

  .n8n-sidebar.open {
    left: 0;
  }

  .n8n-main-content {
    margin-left: 0;
    padding: 16px;
  }

  .n8n-card {
    margin-bottom: 16px;
  }
}

/* Tablet (768px - 1024px) */
@media (min-width: 769px) and (max-width: 1024px) {
  .n8n-sidebar {
    width: 240px;
  }

  .n8n-main-content {
    margin-left: 240px;
  }
}

/* Desktop (acima de 1024px) */
@media (min-width: 1025px) {
  .n8n-sidebar {
    width: 280px;
  }

  .n8n-main-content {
    margin-left: 280px;
  }
}

Domínio Customizado

Configuração de Domínio

Proxy Reverso com Nginx

server {
    listen 80;
    server_name automação.suaempresa.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name automação.suaempresa.com;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    # Headers de segurança
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

    # Proxy para n8n
    location / {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # WebSocket support
    location /ws {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Configuração com Docker

# docker-compose.yml com domínio customizado
version: '3.8'
services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
      - ./logs:/var/log/nginx
    depends_on:
      - n8n
    networks:
      - n8n-network

  n8n:
    image: n8nio/n8n
    environment:
      - N8N_HOST=automação.suaempresa.com
      - N8N_PROTOCOL=https
      - N8N_PORT=5678
    volumes:
      - ./custom-theme:/app/custom-theme
    networks:
      - n8n-network
    expose:
      - "5678"

volumes:
  n8n_data:

networks:
  n8n-network:
    driver: bridge

SSL e Segurança

#!/bin/bash

# Configuração do Let's Encrypt
EMAIL="admin@suaempresa.com"
DOMAIN="automação.suaempresa.com"

# Instalar certbot
apt-get update
apt-get install -y certbot python3-certbot-nginx

# Obter certificado SSL
certbot --nginx -d $DOMAIN --email $EMAIL --agree-tos --non-interactive

# Configurar renovação automática
echo "0 12 * * * /usr/bin/certbot renew --quiet" | crontab -
# Headers de segurança adicionais
add_header Content-Security-Policy "
    default-src 'self';
    script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net;
    style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
    font-src 'self' https://fonts.gstatic.com;
    img-src 'self' data: https:;
    connect-src 'self' https: wss:;
    frame-ancestors 'self';
" always;

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

Integração com Aplicação Principal

CSS para Integração

/* integration.css */
/* Ocultar elementos desnecessários */
.n8n-sidebar .n8n-navigation-item[data-test-id="settings"] {
  display: none;
}

/* Integrar com header da aplicação principal */
.n8n-header {
  background: transparent;
  border-bottom: 1px solid var(--n8n-border-color);
  padding: 0;
  height: auto;
}

/* Estilo consistente com aplicação principal */
.n8n-button {
  font-family: var(--app-font-family);
  border-radius: var(--app-border-radius);
  font-weight: var(--app-font-weight);
}

.n8n-card {
  border-radius: var(--app-border-radius);
  box-shadow: var(--app-shadow);
}

/* Cores consistentes */
:root {
  --n8n-primary-color: var(--app-primary-color);
  --n8n-secondary-color: var(--app-secondary-color);
  --n8n-accent-color: var(--app-accent-color);
  --n8n-background-color: var(--app-background-color);
  --n8n-surface-color: var(--app-surface-color);
  --n8n-text-color: var(--app-text-color);
  --n8n-border-color: var(--app-border-color);
}

JavaScript para Integração

// integration.js
class N8NIntegration {
  constructor() {
    this.init();
  }

  init() {
    // Aguardar carregamento do n8n
    this.waitForN8N().then(() => {
      this.applyCustomTheme();
      this.setupEventListeners();
      this.integrateWithMainApp();
    });
  }

  waitForN8N() {
    return new Promise((resolve) => {
      const checkN8N = () => {
        if (document.querySelector('.n8n-app')) {
          resolve();
        } else {
          setTimeout(checkN8N, 100);
        }
      };
      checkN8N();
    });
  }

  applyCustomTheme() {
    // Aplicar tema customizado
    const theme = {
      primaryColor: '#1f2937',
      fontFamily: 'Inter, sans-serif'
    };

    // Aplicar variáveis CSS
    Object.entries(theme).forEach(([key, value]) => {
      document.documentElement.style.setProperty(
        `--n8n-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`,
        value
      );
    });
  }

  setupEventListeners() {
    // Escutar eventos do n8n
    document.addEventListener('n8n-workflow-executed', (event) => {
      this.notifyMainApp('workflow-executed', event.detail);
    });

    document.addEventListener('n8n-workflow-error', (event) => {
      this.notifyMainApp('workflow-error', event.detail);
    });
  }

  integrateWithMainApp() {
    // Integrar com aplicação principal
    if (window.parent && window.parent !== window) {
      // Está em iframe
      this.setupIframeIntegration();
    } else {
      // Está em nova aba/janela
      this.setupWindowIntegration();
    }
  }

  setupIframeIntegration() {
    // Comunicação com aplicação principal via postMessage
    window.addEventListener('message', (event) => {
      if (event.origin !== window.parent.location.origin) return;

      switch (event.data.type) {
        case 'n8n-load-workflow':
          this.loadWorkflow(event.data.workflowId);
          break;
        case 'n8n-execute-workflow':
          this.executeWorkflow(event.data.workflowId, event.data.data);
          break;
        case 'n8n-get-status':
          this.getStatus();
          break;
      }
    });
  }

  setupWindowIntegration() {
    // Integração quando n8n está em nova aba
    window.addEventListener('beforeunload', () => {
      if (window.opener) {
        window.opener.postMessage({
          type: 'n8n-closed',
          timestamp: Date.now()
        }, '*');
      }
    });
  }

  notifyMainApp(type, data) {
    if (window.parent && window.parent !== window) {
      window.parent.postMessage({
        type: `n8n-${type}`,
        data: data,
        timestamp: Date.now()
      }, '*');
    }
  }

  loadWorkflow(workflowId) {
    // Carregar workflow específico
    const url = new URL(window.location);
    url.searchParams.set('workflow', workflowId);
    window.location.href = url.toString();
  }

  executeWorkflow(workflowId, data) {
    // Executar workflow via API
    fetch(`/api/v1/workflows/${workflowId}/trigger`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-N8N-API-KEY': this.getApiKey()
      },
      body: JSON.stringify({ data })
    })
    .then(response => response.json())
    .then(result => {
      this.notifyMainApp('workflow-executed', result);
    })
    .catch(error => {
      this.notifyMainApp('workflow-error', error);
    });
  }

  getStatus() {
    // Obter status atual do n8n
    const status = {
      workflows: document.querySelectorAll('.n8n-workflow').length,
      activeWorkflows: document.querySelectorAll('.n8n-workflow.active').length,
      lastExecution: this.getLastExecutionTime()
    };

    this.notifyMainApp('status', status);
  }

  getApiKey() {
    // Obter API key do localStorage ou configuração
    return localStorage.getItem('n8n-api-key') || '';
  }

  getLastExecutionTime() {
    // Obter tempo da última execução
    const lastExecution = localStorage.getItem('n8n-last-execution');
    return lastExecution ? new Date(lastExecution) : null;
  }
}

// Inicializar integração
new N8NIntegration();

Boas Práticas

Design System

Guia de Cores

/* design-system.css */
:root {
  /* Cores primárias */
  --brand-primary: #3b82f6;
  --brand-secondary: #059669;
  --warning: #f59e0b;
  --success: #10b981;
  --error: #ef4444;
  --info: #06b6d4;

  /* Cores neutras */
  --neutral-50: #f8fafc;
  --neutral-100: #f1f5f9;
  --neutral-200: #e2e8f0;
  --neutral-300: #cbd5e1;
  --neutral-400: #94a3b8;
  --neutral-500: #64748b;
  --neutral-600: #475569;
  --neutral-700: #334155;
  --neutral-800: #1e293b;
  --neutral-900: #0f172a;
}

/* Aplicar ao n8n */
:root {
  --n8n-primary-color: var(--brand-primary);
  --n8n-secondary-color: var(--brand-secondary);
  --n8n-accent-color: var(--warning);
  --n8n-success-color: var(--success);
  --n8n-error-color: var(--error);
  --n8n-info-color: var(--info);
}

Tipografia

/* typography.css */
:root {
  /* Fontes */
  --font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-family-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
  
  /* Tamanhos */
  --font-size-xs: 12px;
  --font-size-sm: 14px;
  --font-size-base: 16px;
  --font-size-lg: 18px;
  --font-size-xl: 20px;
  --font-size-2xl: 24px;
  --font-size-3xl: 30px;
  
  /* Pesos */
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  
  /* Line heights */
  --line-height-tight: 1.25;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.75;
}

/* Aplicar ao n8n */
.n8n-app {
  font-family: var(--font-family-sans);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
}

.n8n-heading {
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
}

.n8n-code {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
}

WCAG Compliance

/* accessibility.css */
/* Contraste adequado */
.n8n-text {
  color: var(--neutral-800);
  background-color: var(--neutral-50);
}

/* Foco visível */
.n8n-button:focus,
.n8n-input:focus,
.n8n-link:focus {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

/* Estados de hover */
.n8n-button:hover,
.n8n-link:hover {
  opacity: 0.8;
  transform: translateY(-1px);
}

/* Suporte a modo escuro */
@media (prefers-color-scheme: dark) {
  :root {
    --n8n-background-color: var(--neutral-900);
    --n8n-surface-color: var(--neutral-800);
    --n8n-text-color: var(--neutral-100);
    --n8n-border-color: var(--neutral-700);
  }
}

/* Suporte a redução de movimento */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Próximos Passos

Agora que você entende o white labelling do n8n:

  1. Gerenciar Workflows - Controle total sobre workflows
  2. Configuração do Embed - Configurar parâmetros avançados
  3. API do n8n - Explorar endpoints para integração
  4. Hosting - Configurar ambiente de produção

Dica Pro

Mantenha consistência visual com sua marca em todos os elementos. Use ferramentas como Figma para criar um design system completo antes de implementar.

Importante

Teste o white labelling em diferentes dispositivos e navegadores. Certifique-se de que a acessibilidade não foi comprometida pelas customizações.

Recurso Adicional

Considere usar ferramentas como Storybook para documentar e testar componentes customizados do seu design system.