You've been asked to "add analytics" to an internal app. Here's the version that takes minutes, needs no tracking plan, no event pipeline, and no meeting: one attribute on the elements worth counting.
One script tag in the app's footer or layout template:
<script async src="https://YOUR-HOST/widget.js" data-feedback-key="fbk_..."></script>
That alone captures pageviews — including SPA route changes — and adds the feedback icon. No configuration, no cookie banner (visitors are anonymous by design), no build step.
Function-level tracking is declarative. Put a data-feedback-action attribute on any clickable element:
<button data-feedback-action="export-csv">Export CSV</button>
<a href="/reports/new" data-feedback-action="create-report">New report</a>
<button data-feedback-action="approve-expense">Approve</button>
That's it. Zero JavaScript. The widget listens for clicks on tagged elements and each one shows up in the dashboard as a named function with its own usage trend. Works identically in server-rendered templates, React, Vue, or a jQuery app from 2013 — it's just an attribute.
Two naming rules borrowed from teams who've done this at scale: use stable kebab-case verbs (export-csv, not btnExport2), and name the intent, not the widget — if the button becomes a menu item next quarter, the metric should survive the redesign.
For things that aren't clicks — a wizard completing, a background import finishing — call the API:
MorveroFeedback.track('import-completed');
MorveroFeedback.open(); // opens the feedback panel programmatically
One gotcha worth knowing, because it costs people an afternoon: the widget loads async, so calls made at page-load time need the queue stub — and API calls must live in their own script tag (a tag with src ignores its inline content):
<script>
window.MorveroFeedback = window.MorveroFeedback || {
q: [],
track: function (n) { this.q.push(['track', n]); },
open: function () { this.q.push(['open']); }
};
MorveroFeedback.track('uptime-page-viewed'); // queued, replayed on load
</script>
<script async src="https://YOUR-HOST/widget.js" data-feedback-key="fbk_..."></script>
Calls made later — click handlers, route changes — don't need the stub; by then MorveroFeedback is the real API.
Within a day, the dashboard answers questions that used to be guesses: which functions carry the app, which shipped features nobody found, whether the redesigned flow actually gets completed. The classic first discovery is the 80/20 inversion — most of the features, a sliver of the use. That's not bad news; that's your simplification roadmap, written by your users' clicks.
If your team uses Claude or Cursor, add morvero.com/mcp as a connector and the agent can create the product, paste the real snippet, tag the buttons worth counting, and — via verify_install — confirm events are actually arriving before it reports done. (The full story: what agents do with our MCP server.)