Naar de inhoud

Documentatie

Feedback, van tag tot rapport

Eén scripttag op je site. Iedereen die naar een pagina kijkt, kan aanwijzen wat er mis is, zeggen waarom, en je de afbeelding sturen. Deze pagina behandelt elke instelling en elke functie van de widget.

De widget installeren

  1. 1

    Maak een project aan

    Eén per site of applicatie. Een e-mailadres volstaat, geen kaart.

  2. 2

    Plak de tag

    Kopieer hem uit het Installeren-paneel van het project en voeg hem toe aan de lay-out die al je pagina's delen.

  3. 3

    Stuur een testrapport

    Open de knop, wijs iets aan, verstuur. Het rapport verschijnt in je project.

De tag uit de app draagt al de sleutel van je project en de instellingen die je daar koos. Plak hem één keer, vlak voor de sluitende body-tag. Met de hand geschreven ziet hij er zo uit:

<script
  src="https://cdn.feedback.o27.io/widget.js"
  data-project-key="YOUR_PROJECT_KEY"
  defer
></script>

De tag stelt zichzelf in vanuit zijn eigen data-*-attributen en laadt de nieuwste widget, dus updates bereiken je site zonder dat je de tag aanraakt. Laad hem in een single-page-applicatie één keer in de HTML-basispagina: hij blijft staan terwijl je router van pagina wisselt.

Zonder projectsleutel verschijnt de widget niet, en de browserconsole zegt waarom.

Stuurt je site een Content Security Policy, sta dan het adres uit de src van de tag toe in script-src, en https://feedback.o27.io in connect-src: daar gaan de rapporten naartoe.

Hoe een rapport ontstaat

Wat je bezoekers zien, zodat je het hun kunt uitleggen.

  • Openen. De knop klapt open tot een paneel dat de melder overal kan neerzetten. Het dient ook als legende in de afbeelding.
  • Aanwijzen. Kies Aanwijzen en klik op een element om het te selecteren, of sleep om een gebied te tekenen. Escape annuleert.
  • Opmerken. Elke selectie krijgt een genummerde omlijning op de pagina en een opmerkingsveld in het paneel. Notitie voegt een bericht over de hele pagina toe, zonder iets te selecteren.
  • Kaderen. De afbeelding toont het zichtbare gebied als alle selecties erin passen, anders de strook van de pagina die ze allemaal bevat. Eén klik schakelt naar de volledige pagina.
  • Kopiëren of versturen. Kopiëren zet de afbeelding op het klembord; Versturen bewaart ze met de opmerkingen in je project. De voorvertoning is optioneel en toont eerst de exacte afbeelding.
  • Minimaliseren of sluiten. Minimaliseren houdt het rapport bij en verbergt de omlijningen; Sluiten gooit het weg. Alles wissen verwijdert alle selecties en biedt een paar seconden Ongedaan maken aan.

Selecties horen bij het huidige bezoek en worden niet bewaard. Is een rapport verstuurd, dan blijft Versturen uit tot het verandert, zodat je team nooit twee keer hetzelfde ontvangt.

Opties

Stel opties in als attributen op de scripttag, of geef ze aan init() onder de naam die onder elk attribuut staat. Het Installeren-paneel van het project schrijft de gangbare voor je.

data-project-keyinit()-optie projectKey · Standaard geen
De insluitsleutel van je project. Rapporten gaan naar dat project.
data-positioninit()-optie position · Standaard bottom-right
In welke hoek de knop begint: top-left, top-right, bottom-left of bottom-right.
data-offset-xinit()-optie offsetX · Standaard 20
De afstand in pixels tot de linker- of rechterrand waaraan de positie verankerd is.
data-offset-yinit()-optie offsetY · Standaard 20
De afstand in pixels tot de boven- of onderrand waaraan de positie verankerd is.
data-compactinit()-optie compact · Standaard auto
always toont alleen het icoon. auto laat het label weg onder 480 pixels.
data-accentinit()-optie accent · Standaard #6d5dfc
De kleur van de knop en van de omlijningen.
data-localeinit()-optie locale · Standaard browser
Forceer de taal van het paneel: en, fr of nl. Anders de keuze van de bezoeker, dan die van zijn browser.
data-visibilityinit()-optie visibility · Standaard protected
protected voor een applicatie met klantgegevens, public voor een showcase- of documentatiesite. Zie Wat een schermafbeelding toont.
data-excludeinit()-optie exclude · Standaard geen
CSS-selectors, gescheiden door komma's, voor gegevens die vervaagd moeten worden en die de pagina zelf niet kan markeren.
data-consoleinit()-optie console · Standaard off
on legt bij elk rapport de logniveaus en tijdstippen vast, nooit de berichten. Zie Consolediagnose.
data-tag-<key>init()-optie tags · Standaard geen
Eén label per attribuut, zoals data-tag-environment="staging". Zie Labels.
data-reporter-email data-reporter-nameinit()-optie reporter · Standaard geen
Wie het rapport verstuurt. Zie Wie meldt.
data-storage-keyinit()-optie storageKey · Standaard o27-feedback
Waar de positie van de knop bewaard wordt. Alleen nodig als twee widgets één domein delen.
data-api-urlinit()-optie apiUrl · Standaard https://feedback.o27.io
Waar de rapporten naartoe gaan. Alleen te wijzigen voor een zelf gehost platform.
alleen init()init()-optie vocabulary · Standaard geen
De teksten van je interface in de actieve taal, zodat ze leesbaar blijven in schermafbeeldingen. Zie Interface en gegevens.
alleen init()init()-optie consoleMessages · Standaard geen
Exacte, vaste logberichten waarvan de tekst bewaard mag blijven. Zie Consolediagnose.

De knop plaatsen

Een applicatie waarvan de koptekst de bovenrand inneemt en het invoerveld de onderrand, heeft geen vrije hoek. Houd de hoek en schuif de knop opzij met een verschuiving:

<script
  src="https://cdn.feedback.o27.io/widget.js"
  data-project-key="YOUR_PROJECT_KEY"
  data-position="bottom-right"
  data-offset-y="88"
  defer
></script>

Je waarden zijn een vertrekpunt, geen vergrendeling: een knop die de bezoeker heeft versleept, houdt zijn eigen positie, en een hoek kiezen in de instellingen van het paneel keert terug naar de jouwe.

Wie meldt

Noem de persoon die het rapport verstuurt, zodat je team kan opvolgen. Op een pagina die je server rendert, schrijf je het op de tag:

<script
  src="https://cdn.feedback.o27.io/widget.js"
  data-project-key="YOUR_PROJECT_KEY"
  data-reporter-email="ada@example.com"
  data-reporter-name="Ada Lovelace"
  defer
></script>

In een applicatie die de gebruiker pas na het laden kent, roep je setReporter aan zodra die bekend is, en met null bij het afmelden:

function withFeedback(run, tries = 50) {
  const feedback = window.o27?.feedback
  if (feedback) run(feedback)
  else if (tries > 0) setTimeout(() => withFeedback(run, tries - 1), 200)
}

withFeedback((feedback) => feedback.setReporter({ email: user.email, name: user.name }))

// on sign-out
withFeedback((feedback) => feedback.setReporter(null))

Beide velden zijn optioneel en worden bijgesneden. Een adres dat er geen is, valt weg, en een leeg paar wist de melder.

Niet gecontroleerd. Wie de insluitsleutel heeft, kan elke waarde sturen: de melder is een label, geen bewijs van identiteit. Hij verschijnt op het rapport in Feedback, in het Slack-bericht en in het Linear-issue: stuur alleen wat de lezers daarvan mogen zien.

Labels

Labels gaan met elk rapport mee: een omgeving, een release, een trace-ID. Zet vaste labels op de tag, één attribuut per label:

<script
  src="https://cdn.feedback.o27.io/widget.js"
  data-project-key="YOUR_PROJECT_KEY"
  data-tag-environment="production"
  data-tag-release="2026.10.1"
  defer
></script>

Voor waarden die na het laden veranderen, roep je setTags aan. Het voegt samen met de huidige set, en een waarde null verwijdert een sleutel:

withFeedback((feedback) => feedback.setTags({ trace_id: traceId }))

// and later
withFeedback((feedback) => feedback.setTags({ trace_id: null }))

Hoogstens 20 labels per rapport. Sleutels gebruiken letters, cijfers en _ . : -; sleutels en waarden blijven onder 200 tekens. Al de rest valt weg.

Het label environment heeft een eigen rol: elk project kan de rapporten van elke omgeving naar een andere plek sturen. Zie Slack en Linear.

Het object window.o27.feedback

Zodra het script geladen is, stelt het vier functies beschikbaar op window.o27.feedback.

init(options) → { destroy() }
Bouwt de widget opnieuw op met deze opties, samengevoegd over die van de tag en van de vorige aanroep. Gebruik het voor de opties die alleen JavaScript kan doorgeven, of om het accent te wijzigen als je thema verandert.
destroy()
Verwijdert de widget van de pagina. init() brengt hem terug.
setTags(tags)
Voegt labels samen in de set die elk rapport draagt. Een waarde null verwijdert een sleutel.
setReporter(reporter | null)
Vervangt de melder, anders dan setTags, dat samenvoegt. null wist hem.

De scripttag is uitgesteld, dus het object bestaat nog niet wanneer je eigen code voor het eerst draait, en een te vroege aanroep valt zonder foutmelding weg. Wacht erop:

function withFeedback(run, tries = 50) {
  const feedback = window.o27?.feedback
  if (feedback) run(feedback)
  else if (tries > 0) setTimeout(() => withFeedback(run, tries - 1), 200)
}

withFeedback((feedback) =>
  feedback.init({ vocabulary: () => Object.values(i18n.messages) }),
)

Het script levert geen typedeclaraties. Declareer de globale variabele in TypeScript één keer:

declare global {
  interface Window {
    o27?: {
      feedback?: {
        init(options?: Record<string, unknown>): { destroy(): void }
        destroy(): void
        setTags(tags: Record<string, string | number | boolean | null>): void
        setReporter(reporter: { email?: string; name?: string } | null): void
      }
    }
  }
}
export {}

Wat een schermafbeelding toont

Elke afbeelding die de widget maakt, beschermt wat de melder niet heeft aangewezen. Dat geldt voor Kopiëren, Versturen en de download die wordt aangeboden als versturen mislukt, op elk abonnement, en de melder kan het niet uitschakelen.

Een applicatie (data-visibility="protected", de standaard) vervaagt alle gegevens buiten de selecties van de melder. In de afbeelding die naar je project gaat, wordt die tekst eerst vervangen door vervangtekst van dezelfde lengte, zodat hij niet uit de vervaging te halen is.

Een publieke site (data-visibility="public") vervaagt niets, tenzij de pagina het als privé markeert.

Wat de melder selecteert, wordt altijd getoond zoals het is. De pagina zelf verandert nooit: alleen de afbeelding.

Interface en gegevens

In een applicatie wordt in drie lagen beslist wat als interface telt en leesbaar blijft. Elke laag gaat voor op de vorige.

  1. 1Structuur. Tekst in nav, header, footer, button, label, th, legend, summary en hun ARIA-rollen is interface. Formuliervelden, iframes, afbeeldingen, tabelcellen en alle andere tekst zijn gegevens, koppen inbegrepen. De dichtstbijzijnde voorouder beslist, dus een veld in een nav blijft een gegeven.
  2. 2Je teksten. Geef de interfaceteksten van de actieve taal mee als vocabulary; een tekst die gelijk is aan een ervan blijft leesbaar, waar hij ook staat. Geef een functie mee als de catalogus later laadt of de taal verandert: ze wordt gelezen op het moment van de schermafbeelding.
  3. 3Je markeringen. data-feedback="private" vervaagt een element en alles erin; data-feedback="public" houdt het leesbaar. De dichtstbijzijnde gemarkeerde voorouder wint, dus een publieke werkbalk kan een privételler bevatten. Markeringen werken op beide soorten sites.
<header>Acme <span data-feedback="private">Jean Dupont</span></header>
<section data-feedback="private">Customer account details</section>
<nav data-feedback="public">…</nav>

<script
  src="https://cdn.feedback.o27.io/widget.js"
  data-project-key="YOUR_PROJECT_KEY"
  data-exclude=".customer-details, #billing-summary"
  defer
></script>

Geen toegang tot de HTML? Som selectors op in data-exclude; ze worden als privé behandeld. Een ongeldige selector blokkeert de schermafbeelding in plaats van gegevens door te laten.

Consolediagnose

Standaard uit. Met data-console="on" draagt elk rapport het niveau en tijdstip van de laatste 60 console-aanroepen. Hun inhoud, foutmeldingen, stacks en objecten worden vervangen door [redacted].

Om de tekst van bepaalde berichten te bewaren, keur je ze goed via init(). Alleen een aanroep met één tekstargument dat exact gelijk is aan een item, houdt zijn tekst:

withFeedback((feedback) =>
  feedback.init({
    console: true,
    consoleMessages: ['Checkout failed', 'Search unavailable'],
  }),
)

Keur alleen vaste berichten goed die niemand noemen: een argument toevoegen of een ID invoegen maakt het hele bericht weer onleesbaar.

Wat een rapport bevat

Het bevat de beschermde afbeelding van het gekozen kader, de opmerkingen van de melder, waar elke selectie staat, de oorsprong van de pagina, de grootte van het venster, en browsergegevens: user agent, taal, pixeldichtheid, schermgrootte, weergavevoorkeuren en tijdzone. Plus je labels, de melder, en de consolediagnose als je die hebt aangezet.

Het bevat niet de paginatitel, het pad, de query of het fragment van de URL, en geen enkele CSS-klasse of -id.

Je integratie controleren

  • Zet herkenbare testinhoud in een beschermde zone, kies Kopiëren en bekijk de afbeelding: gegevens buiten je selecties moeten onleesbaar zijn, bedieningselementen en selecties scherp.
  • Herhaal met ingevulde formuliervelden en met de selectors die je in data-exclude opsomde.
  • Open in de netwerktools van je browser het verzoek van de schermafbeelding: geen titel, alleen de oorsprong van de URL, en geen consoleveld tenzij je de diagnose hebt aangezet.

Slack en Linear

Rapporten komen altijd in je Feedback-project terecht. Koppel Slack of Linear één keer, onder Integraties, en elk project kan ze ook doorsturen. Integraties horen bij het Team-abonnement.

Slack plaatst elk rapport in een kanaal, afbeelding inbegrepen. Nodig de Feedback-app uit in dat kanaal, anders wordt het bericht geweigerd.

Linear maakt van een rapport een issue in een team, met afbeelding en opmerkingen. Kies de status, het project en de labels waarmee nieuwe issues beginnen.

Bestemmingen stel je in per project en per omgeving, gelezen uit het label environment, zodat rapporten van staging naar het ene kanaal gaan en die van productie naar een ander. Elke bestemming is automatisch en krijgt elk nieuw rapport, of bij versturen en krijgt een rapport wanneer iemand het vanaf zijn pagina in Feedback verstuurt.

Probleemoplossing

De knop verschijnt niet

Controleer of de tag de sleutel van je project draagt, of het projectadres gebruikt dat je uit de app kopieerde. De browserconsole meldt een ontbrekende sleutel. Op een site met een Content Security Policy, zie De widget installeren.

De knop bedekt een van mijn eigen knoppen

Voeg data-offset-x of data-offset-y toe, of kies een andere hoek. Zie De knop plaatsen.

Rapporten komen binnen zonder melder

setReporter is waarschijnlijk aangeroepen voordat het script geladen was, en weggevallen. Wacht op window.o27.feedback, zoals in Het object window.o27.feedback.

Delen van mijn interface zijn vervaagd

Tekst buiten een structureel element telt als gegeven. Markeer de zone met data-feedback="public", of geef je interfaceteksten mee als vocabulary.

Klantgegevens zijn leesbaar in schermafbeeldingen

Controleer dat de tag niet data-visibility="public" zegt. Markeer de zone daarna met data-feedback="private", of som ze op in data-exclude.

De schermafbeelding mislukt meteen

Een ongeldige selector in data-exclude blokkeert elke schermafbeelding. Controleer de lijst in de geavanceerde opties van het project.

Een afbeelding, lettertype of video ziet er verkeerd uit in de schermafbeelding

Zie Bekende beperkingen.

Bekende beperkingen

  • Afbeeldingen van een ander domein zonder CORS, sommige weblettertypes, en de inhoud van iframes, canvassen en WebGL verschijnen misschien niet precies zoals op het scherm.
  • Selecties en opmerkingen leven alleen tijdens het huidige bezoek. Alleen de positie van de knop wordt bewaard.