@feedget/widget
v1.3.0
Published
Widget de feedback integrado à API Feedget para coleta de feedback de usuários em aplicações web
Maintainers
Readme
@feedget/widget
Widget de feedback inteligente e multi-plataforma para aplicações web
Demo · Documentação · Reportar Bug · Solicitar Feature
Sobre o Feedget Widget
O Feedget Widget é uma biblioteca JavaScript/TypeScript moderna e leve que permite coletar feedbacks de usuários diretamente em sua aplicação web. Com suporte nativo para React, Angular e Vanilla JavaScript, o widget oferece uma experiência de usuário fluida e profissional.
Por que escolher o Feedget Widget?
- Multi-plataforma: Funciona com React, Angular e Vanilla JS
- TypeScript First: Tipagem completa incluída
- Captura de Screenshots: Integração automática com html2canvas
- Análise Inteligente: Feedback enviado para análise de sentimento via API
- Zero Configuração: Funciona out-of-the-box com configurações sensatas
- Leve e Rápido: Bundle otimizado < 50KB gzipped
- Totalmente Customizável: Posicionamento, tema e metadata personalizáveis
- Acessível: Componentes acessíveis e responsivos
Demonstração
Nota: Adicione um GIF ou screenshot do widget em ação para melhor visualização.
Instalação
Via NPM
npm install @feedget/widgetVia Yarn
yarn add @feedget/widgetVia pnpm
pnpm add @feedget/widgetInício Rápido
React
import { FeedgetWidget } from "@feedget/widget/react";
import "@feedget/widget/styles.css";
function App() {
return (
<div>
<h1>Minha Aplicação</h1>
<FeedgetWidget
apiKey="feedget_pk_live_abc123..."
apiUrl="https://api.feedget.io"
/>
</div>
);
}
export default App;Angular
// app.component.ts
import { Component, OnInit, OnDestroy } from "@angular/core";
import {
createFeedgetWidget,
FeedgetWidgetAngular,
} from "@feedget/widget/angular";
import "@feedget/widget/styles.css";
@Component({
selector: "app-root",
template: '<div id="app">Minha Aplicação</div>',
})
export class AppComponent implements OnInit, OnDestroy {
private widget: FeedgetWidgetAngular | null = null;
ngOnInit() {
this.widget = createFeedgetWidget({
apiKey: "feedget_pk_live_abc123...",
apiUrl: "https://api.feedget.io",
});
this.widget.mount();
}
ngOnDestroy() {
this.widget?.unmount();
}
}Vanilla JavaScript
import { Feedget } from "@feedget/widget/vanilla";
import "@feedget/widget/styles.css";
Feedget.init({
apiKey: "feedget_pk_live_abc123...",
apiUrl: "https://api.feedget.io",
});Funcionalidades
Core Features
- Tipos de Feedback: Suporte para BUG, IDEA e OTHER
- Captura de Screenshots: Captura automática da tela com html2canvas
- Validação de Entrada: Comentários entre 10-1000 caracteres
- Metadata Automática: Coleta automática de URL, User Agent e Viewport
- Rate Limiting: Proteção contra spam (100 req/min por API key)
- Tratamento de Erros: Mensagens de erro específicas e amigáveis
- Loading States: Indicadores de carregamento durante envio
Segurança
- API Key Authentication: Autenticação segura via API keys
- HTTPS Only: Comunicação criptografada obrigatória
- Input Sanitization: Proteção contra XSS e injeção
- CORS Support: Configuração adequada de CORS
UI/UX
- Interface Responsiva: Funciona perfeitamente em desktop e mobile
- Posicionamento Fixo: Widget sempre visível no canto da tela
- Animações Suaves: Transições e animações fluidas
- Dark Mode Ready: Suporte a temas claro e escuro (em breve)
- Acessibilidade: Seguindo padrões WCAG 2.1
Configuração Detalhada
Propriedades do Widget
| Propriedade | Tipo | Obrigatório | Descrição |
| ----------- | -------- | ----------- | ---------------------------------------------- |
| apiKey | string | Sim | API Key obtida no dashboard Feedget |
| apiUrl | string | Não | URL da API (default: https://api.feedget.io) |
| metadata | object | Não | Metadata customizada para enviar com feedbacks |
Exemplo com Todas as Opções
<FeedgetWidget
apiKey="feedget_pk_live_abc123..."
apiUrl="https://api.feedget.io"
metadata={{
// Identificação do usuário
userId: "user-123",
userEmail: "[email protected]",
// Informações da aplicação
version: "1.0.0",
environment: "production",
// Dados customizados
custom: {
plan: "premium",
feature: "checkout",
sessionId: "sess_xyz789",
},
}}
/>Guia de Integração por Framework
React (Create React App / Vite / Next.js)
Create React App
// src/App.tsx
import { FeedgetWidget } from "@feedget/widget/react";
import "@feedget/widget/styles.css";
function App() {
return (
<>
{/* Seu conteúdo */}
<FeedgetWidget
apiKey={process.env.REACT_APP_FEEDGET_API_KEY!}
apiUrl={process.env.REACT_APP_FEEDGET_API_URL}
/>
</>
);
}Next.js (App Router)
// app/layout.tsx
"use client";
import { FeedgetWidget } from "@feedget/widget/react";
import "@feedget/widget/styles.css";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="pt-BR">
<body>
{children}
<FeedgetWidget
apiKey={process.env.NEXT_PUBLIC_FEEDGET_API_KEY!}
apiUrl={process.env.NEXT_PUBLIC_FEEDGET_API_URL}
/>
</body>
</html>
);
}Next.js (Pages Router)
// pages/_app.tsx
import type { AppProps } from "next/app";
import { FeedgetWidget } from "@feedget/widget/react";
import "@feedget/widget/styles.css";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<FeedgetWidget
apiKey={process.env.NEXT_PUBLIC_FEEDGET_API_KEY!}
apiUrl={process.env.NEXT_PUBLIC_FEEDGET_API_URL}
/>
</>
);
}Vite
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "@feedget/widget/styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);// src/App.tsx
import { FeedgetWidget } from "@feedget/widget/react";
function App() {
return (
<>
{/* Seu conteúdo */}
<FeedgetWidget
apiKey={import.meta.env.VITE_FEEDGET_API_KEY}
apiUrl={import.meta.env.VITE_FEEDGET_API_URL}
/>
</>
);
}Angular
Módulo Principal
// app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}Componente
// app.component.ts
import { Component, OnInit, OnDestroy } from "@angular/core";
import {
createFeedgetWidget,
FeedgetWidgetAngular,
FeedgetConfig,
} from "@feedget/widget/angular";
@Component({
selector: "app-root",
template: `
<div id="app">
<h1>Minha Aplicação Angular</h1>
</div>
`,
styleUrls: ["./app.component.scss"],
})
export class AppComponent implements OnInit, OnDestroy {
private widget: FeedgetWidgetAngular | null = null;
ngOnInit() {
const config: FeedgetConfig = {
apiKey: "feedget_pk_live_abc123...",
apiUrl: "https://api.feedget.io",
metadata: {
userId: "user-123",
version: "1.0.0",
},
};
this.widget = createFeedgetWidget(config);
this.widget.mount();
}
ngOnDestroy() {
if (this.widget) {
this.widget.unmount();
}
}
}Estilos Globais
// styles.scss
@import "@feedget/widget/styles.css";Vanilla JavaScript
Com Módulos ES6
// main.js
import { Feedget } from "@feedget/widget/vanilla";
import "@feedget/widget/styles.css";
// Inicializar quando o DOM estiver pronto
document.addEventListener("DOMContentLoaded", () => {
Feedget.init({
apiKey: "feedget_pk_live_abc123...",
apiUrl: "https://api.feedget.io",
metadata: {
userId: getUserId(), // Função customizada
version: "1.0.0",
},
});
});
// Para destruir o widget (cleanup)
window.addEventListener("beforeunload", () => {
Feedget.destroy();
});Via CDN (Experimental)
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Meu Site</title>
<!-- Estilos do Widget -->
<link
rel="stylesheet"
href="https://unpkg.com/@feedget/widget@latest/dist/style.css"
/>
</head>
<body>
<h1>Meu Site</h1>
<!-- Widget Script -->
<script type="module">
import { Feedget } from "https://unpkg.com/@feedget/widget@latest/dist/vanilla.js";
Feedget.init({
apiKey: "feedget_pk_live_abc123...",
apiUrl: "https://api.feedget.io",
});
</script>
</body>
</html>API Reference
React Component Props
interface FeedgetWidgetProps {
apiKey: string;
apiUrl?: string;
metadata?: {
userId?: string;
userEmail?: string;
version?: string;
environment?: string;
custom?: Record<string, any>;
};
}Angular Config
interface FeedgetConfig {
apiKey: string;
apiUrl?: string;
metadata?: FeedgetMetadata;
}
interface FeedgetWidgetAngular {
mount(container?: HTMLElement): void;
unmount(): void;
updateConfig(config: Partial<FeedgetConfig>): void;
}Vanilla JS API
interface FeedgetVanilla {
init(config: FeedgetConfig): void;
destroy(): void;
updateConfig(config: Partial<FeedgetConfig>): void;
}Integração com a API Feedget
Endpoint do Widget
O widget envia feedbacks para:
POST https://api.feedget.io/public/feedbacksHeaders:
X-API-Key: feedget_pk_live_abc123...
Content-Type: application/jsonPayload:
{
"type": "BUG" | "IDEA" | "OTHER",
"comment": "Descrição do feedback...",
"screenshot": "data:image/png;base64,iVBOR...",
"metadata": {
"url": "https://meusite.com/page",
"userAgent": "Mozilla/5.0...",
"viewport": {
"width": 1920,
"height": 1080
},
"custom": {
"userId": "user-123",
"version": "1.0.0"
}
}
}Códigos de Status HTTP
| Código | Descrição |
| ------ | ---------------------------------------------- |
| 200 | Feedback enviado com sucesso |
| 400 | Dados inválidos (comentário muito curto/longo) |
| 401 | API key inválida ou expirada |
| 403 | Assinatura necessária ou inativa |
| 429 | Rate limit excedido (100 req/min) |
| 500 | Erro interno do servidor |
Customização Avançada
Posicionamento do Widget
Por padrão, o widget fica fixo no canto inferior esquerdo da tela.
CSS Customizado:
/* Ajustar posicionamento */
.feedget-widget-container {
bottom: 32px;
left: 32px;
/* ou right: 32px para canto direito */
}
/* Mobile */
@media (max-width: 768px) {
.feedget-widget-container {
bottom: 16px;
left: 16px;
}
}Temas
/* Customizar cores do widget */
:root {
--feedget-primary: #8257e6;
--feedget-secondary: #996dff;
--feedget-text: #27272a;
--feedget-bg: #ffffff;
--feedget-border: #e4e4e7;
}
/* Dark mode */
[data-theme="dark"] {
--feedget-text: #fafafa;
--feedget-bg: #18181b;
--feedget-border: #3f3f46;
}Troubleshooting
Widget não aparece na tela
Problema: Widget não é renderizado
Soluções:
Certifique-se de importar o CSS:
import "@feedget/widget/styles.css";Verifique se a API Key está configurada:
apiKey = "feedget_pk_live_..."; // não vazioVerifique o console do navegador para erros
Confirme que a assinatura está ativa
Erro 401: Unauthorized
Problema: API key inválida ou expirada
Soluções:
- Gere uma nova API key no dashboard Feedget
- Verifique se a key começa com
feedget_pk_ - Confirme se a key não está expirada
- Verifique se a assinatura está ativa
Erro 403: Forbidden
Problema: Assinatura inativa ou limite excedido
Soluções:
- Verifique status da assinatura no dashboard
- Confirme método de pagamento
- Verifique se o limite mensal foi atingido
- Entre em contato com o suporte
Erro 429: Too Many Requests
Problema: Rate limit excedido (100 req/min)
Soluções:
- Aguarde 1 minuto antes de tentar novamente
- Implemente debounce no lado do cliente
- Para produção, considere upgrade do plano
- Entre em contato para ajuste de limites
Screenshots não são capturados
Problema: html2canvas não funciona
Soluções:
- Verifique CORS das imagens externas
- Confirme que html2canvas foi instalado:
npm list html2canvas - Algumas imagens podem não ser capturadas por política CORS
- Teste em diferentes navegadores
Problemas de TypeScript
Problema: Erros de tipagem
Soluções:
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "bundler", // ou "node"
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}Widget conflita com outros componentes
Problema: z-index ou posicionamento
Soluções:
/* Ajuste o z-index do widget */
.feedget-widget-container {
z-index: 9999 !important;
}
/* Ou dos elementos conflitantes */
.seu-modal {
z-index: 10000;
}FAQ
Quanto custa usar o Feedget?
O Feedget oferece planos gratuitos e pagos. Visite feedget.io/pricing para mais detalhes.
O widget funciona em todos os navegadores?
Sim, o widget é compatível com:
- Chrome/Edge (últimas 2 versões)
- Firefox (últimas 2 versões)
- Safari 13+
- Opera (última versão)
Posso usar em aplicações mobile?
Sim, o widget é totalmente responsivo. Para apps mobile nativos, aguarde nosso SDK React Native.
Os dados dos feedbacks ficam onde?
Os feedbacks são armazenados de forma segura nos servidores da Feedget, com criptografia em repouso e em trânsito. Conformidade com GDPR e LGPD.
Posso self-host a API?
Atualmente não oferecemos versão self-hosted. Entre em contato para planos enterprise.
O widget afeta a performance do site?
Não. O widget é carregado de forma assíncrona e tem um bundle otimizado < 50KB gzipped. Impacto mínimo na performance.
Posso customizar o visual do widget?
Sim, você pode customizar cores, posicionamento e tema via CSS. Suporte a temas customizados completos em breve.
Segurança
Relatando Vulnerabilidades
Se você encontrar uma vulnerabilidade de segurança, por favor NÃO abra uma issue pública.
Envie um email para: [email protected]
Práticas de Segurança
- ✅ Use HTTPS em produção
- ✅ Armazene API keys em variáveis de ambiente
- ✅ Nunca commite API keys no código
- ✅ Rotacione API keys periodicamente
- ✅ Use diferentes keys para dev/staging/prod
- ✅ Configure CSP headers adequadamente
Content Security Policy:
Content-Security-Policy:
connect-src 'self' https://api.feedget.io;
img-src 'self' data: https://api.feedget.io;Contribuindo
Contribuições são bem-vindas! Por favor, leia nosso Guia de Contribuição antes de submeter PRs.
Como Contribuir
- Fork o repositório
- Clone seu fork:
git clone https://github.com/seu-usuario/widget.git - Crie uma branch para sua feature:
git checkout -b feature/minha-feature - Commit suas mudanças:
git commit -m 'feat: adiciona minha feature' - Push para a branch:
git push origin feature/minha-feature - Abra um Pull Request
Padrão de Commits
Usamos Conventional Commits:
feat:Nova funcionalidadefix:Correção de bugdocs:Mudanças na documentaçãostyle:Formatação, ponto-e-vírgula, etcrefactor:Refatoração de códigotest:Adição de testeschore:Manutenção
Roadmap
- [x] Suporte React
- [x] Suporte Angular
- [x] Suporte Vanilla JS
- [x] Captura de screenshots
- [x] TypeScript completo
- [ ] Dark mode nativo
- [ ] Temas customizáveis
- [ ] Suporte Vue.js
- [ ] Suporte Svelte
- [ ] React Native SDK
- [ ] Flutter SDK
- [ ] Internacionalização (i18n)
- [ ] Acessibilidade WCAG 2.1 AA
- [ ] Webhooks customizáveis
Licença
Este projeto está licenciado sob a Licença MIT.
Suporte
Documentação
- Documentação Completa: docs.feedget.io
- Guia de API: docs.feedget.io/api
- Exemplos: github.com/feedget/examples
Comunidade
- Discord: discord.gg/feedget
- Twitter: @feedget
- GitHub Issues: github.com/feedget/widget/issues
Contato Direto
- Email: [email protected]
- Chat: feedget.io/support
Créditos
Desenvolvido e mantido por Feedget Team
Tecnologias Utilizadas
Feito com ❤️ pela equipe Feedget
