@tekibo/feedpulse-sdk 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -58
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,35 +21,6 @@ The SDK automatically tracks:
|
|
|
21
21
|
- `scroll_into_view`: when tagged elements enter viewport
|
|
22
22
|
- `feedback`: explicit rating/message submissions from widget or manual API
|
|
23
23
|
|
|
24
|
-
Each event includes context such as session id, visitor id, page path, device, browser, OS, metadata, and timestamp.
|
|
25
|
-
|
|
26
|
-
## Backend requirements
|
|
27
|
-
|
|
28
|
-
Your backend must expose an ingest endpoint compatible with this payload:
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"events": [
|
|
33
|
-
{
|
|
34
|
-
"projectApiKey": "fp_live_xxx",
|
|
35
|
-
"elementId": "hero-cta",
|
|
36
|
-
"eventType": "click",
|
|
37
|
-
"sessionId": "session-1",
|
|
38
|
-
"visitorId": "visitor-1",
|
|
39
|
-
"page": "/",
|
|
40
|
-
"device": "desktop",
|
|
41
|
-
"metadata": {},
|
|
42
|
-
"timestamp": "2026-03-12T00:00:00.000Z"
|
|
43
|
-
}
|
|
44
|
-
]
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
In the FeedPulse codebase, the default server endpoint is:
|
|
49
|
-
|
|
50
|
-
- `POST /api/ingest`
|
|
51
|
-
|
|
52
|
-
## Quick start (Nuxt)
|
|
53
24
|
|
|
54
25
|
Import from `@tekibo/feedpulse-sdk/nuxt` and wrap your app:
|
|
55
26
|
|
|
@@ -60,12 +31,16 @@ import { FeedPulseProvider, FeedPulseWidget } from "@tekibo/feedpulse-sdk/nuxt";
|
|
|
60
31
|
|
|
61
32
|
<template>
|
|
62
33
|
<FeedPulseProvider api-key="fp_live_your_project_key">
|
|
63
|
-
|
|
34
|
+
<FeedPulseProvider
|
|
35
|
+
api-key="fp_live_your_project_key"
|
|
36
|
+
endpoint="https://feed-pulse.vercel.app/api/ingest"
|
|
37
|
+
>
|
|
64
38
|
<FeedPulseWidget id="global-feedback" position="bottom-right" />
|
|
65
39
|
</FeedPulseProvider>
|
|
66
40
|
</template>
|
|
67
41
|
```
|
|
68
42
|
|
|
43
|
+
|
|
69
44
|
Tag any interactive element with `data-fp-id`:
|
|
70
45
|
|
|
71
46
|
```vue
|
|
@@ -112,7 +87,10 @@ function SaveButton() {
|
|
|
112
87
|
|
|
113
88
|
export default function App() {
|
|
114
89
|
return (
|
|
115
|
-
<FeedPulseProvider
|
|
90
|
+
<FeedPulseProvider
|
|
91
|
+
apiKey="fp_live_your_project_key"
|
|
92
|
+
endpoint="https://feed-pulse.vercel.app/api/ingest"
|
|
93
|
+
>
|
|
116
94
|
<button data-fp-id="hero-cta">Get Started</button>
|
|
117
95
|
<SaveButton />
|
|
118
96
|
<FeedPulseWidget id="global-feedback" position="bottom-right" />
|
|
@@ -132,7 +110,7 @@ import { FeedPulseTracker } from "@tekibo/feedpulse-sdk";
|
|
|
132
110
|
`FeedPulseTracker` configuration:
|
|
133
111
|
|
|
134
112
|
- `apiKey: string` required
|
|
135
|
-
- `endpoint?: string` optional, defaults to `https://
|
|
113
|
+
- `endpoint?: string` optional, defaults to `https://feed-pulse.vercel.app/api/ingest`
|
|
136
114
|
- `batchInterval?: number` optional, defaults to `5000` ms
|
|
137
115
|
|
|
138
116
|
Key methods:
|
|
@@ -150,32 +128,6 @@ Nuxt and React widgets support:
|
|
|
150
128
|
- `placeholder?: string` prompt text
|
|
151
129
|
- `position?: "bottom-right" | "bottom-left" | "inline"` default is `"bottom-right"`
|
|
152
130
|
|
|
153
|
-
## Endpoint override
|
|
154
|
-
|
|
155
|
-
Use this when sending to staging/self-hosted backend:
|
|
156
|
-
|
|
157
|
-
### Nuxt
|
|
158
|
-
|
|
159
|
-
```vue
|
|
160
|
-
<FeedPulseProvider
|
|
161
|
-
api-key="fp_live_your_project_key"
|
|
162
|
-
endpoint="https://staging.your-domain.com/api/ingest"
|
|
163
|
-
>
|
|
164
|
-
<NuxtPage />
|
|
165
|
-
</FeedPulseProvider>
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### React
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
<FeedPulseProvider
|
|
172
|
-
apiKey="fp_live_your_project_key"
|
|
173
|
-
endpoint="https://staging.your-domain.com/api/ingest"
|
|
174
|
-
>
|
|
175
|
-
{children}
|
|
176
|
-
</FeedPulseProvider>
|
|
177
|
-
```
|
|
178
|
-
|
|
179
131
|
## Integration checklist for your app
|
|
180
132
|
|
|
181
133
|
1. Create a project in FeedPulse dashboard and copy the project API key
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class n{constructor(e){this.queue=[],this.flushInterval=null,this.observer=null,this.intersectionObserver=null,this.seenInView=new Set,this.config={endpoint:"https://
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class n{constructor(e){this.queue=[],this.flushInterval=null,this.observer=null,this.intersectionObserver=null,this.seenInView=new Set,this.config={endpoint:"https://feed-pulse.vercel.app/api/ingest",batchInterval:5e3,...e},this.visitorId=this.getOrCreateVisitorId(),this.sessionId=this.generateSessionId()}init(){this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM()}attachGlobalListeners(){document.addEventListener("click",i=>{const s=i.target.closest("[data-fp-id]");s&&this.track("click",s.getAttribute("data-fp-id"),{x:i.clientX,y:i.clientY})},{passive:!0});let e=0,t=null;document.addEventListener("mouseover",i=>{const s=i.target.closest("[data-fp-id]");s&&(e=Date.now(),t=s.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",i=>{if(!i.target.closest("[data-fp-id]")||!t)return;const r=Date.now()-e;r>500&&this.track("hover",t,{hoverDuration:r}),t=null},{passive:!0})}observeDOM(){this.intersectionObserver=new IntersectionObserver(t=>{for(const i of t){const s=i.target.dataset.fpId;!s||!i.isIntersecting||this.seenInView.has(s)||(this.seenInView.add(s),this.track("scroll_into_view",s,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))}},{threshold:.5});const e=()=>{document.querySelectorAll("[data-fp-id]").forEach(t=>{this.intersectionObserver?.observe(t)})};e(),this.observer=new MutationObserver(()=>e()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,t,i){this.queue.push({projectApiKey:this.config.apiKey,elementId:t,eventType:e,sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:i,timestamp:new Date().toISOString()})}trackFeedback(e,t,i){!t&&!i||this.sendImmediate([{projectApiKey:this.config.apiKey,elementId:e??"__page__",eventType:"feedback",sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:t,message:i},timestamp:new Date().toISOString()}])}async flush(){if(this.queue.length===0)return;const e=[...this.queue];this.queue=[],await this.sendImmediate(e)}async sendImmediate(e){try{await fetch(this.config.endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0})}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),window.addEventListener("beforeunload",()=>this.flush()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.flush()})}getOrCreateVisitorId(){const e="__fp_vid";let t=localStorage.getItem(e);return t||(t=crypto.randomUUID(),localStorage.setItem(e,t)),t}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).slice(2)}`}getDeviceType(){const e=navigator.userAgent;return/Mobi|Android/i.test(e)?"mobile":/Tablet|iPad/i.test(e)?"tablet":"desktop"}getBrowser(){const e=navigator.userAgent;return e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Firefox")?"Firefox":e.includes("Safari")?"Safari":"Other"}getOS(){const e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":/iPhone|iOS/.test(e)?"iOS":"Other"}destroy(){this.flushInterval&&clearInterval(this.flushInterval),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.flush()}}exports.FeedPulseTracker=n;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class o {
|
|
2
2
|
constructor(e) {
|
|
3
3
|
this.queue = [], this.flushInterval = null, this.observer = null, this.intersectionObserver = null, this.seenInView = /* @__PURE__ */ new Set(), this.config = {
|
|
4
|
-
endpoint: "https://
|
|
4
|
+
endpoint: "https://feed-pulse.vercel.app/api/ingest",
|
|
5
5
|
batchInterval: 5e3,
|
|
6
6
|
...e
|
|
7
7
|
}, this.visitorId = this.getOrCreateVisitorId(), this.sessionId = this.generateSessionId();
|