Embeddable Widget
Embed Logproof's event timeline directly into your application using the JavaScript widget. Perfect for showing audit logs, activity feeds, and event histories to your end users.
Overview
The Logproof widget is a pre-built, customizable component that displays event timelines in your web application. It handles authentication, pagination, filtering, and real-time updates automatically.
Widget Tokens vs API Keys
Widget tokens are scoped, limited-access tokens designed specifically for client-side use. Unlike full API keys, widget tokens can only access the timeline endpoint and are safe to embed in frontend applications.
| Feature | API Keys | Widget Tokens |
|---|---|---|
| Scope | Full API access with configured scopes | Read-only access to timeline endpoint only |
| Usage | Server-side applications | Client-side widgets |
| Format | lp_sk_live_... |
lp_wt_... |
| Security | Keep secret, never expose | Safe to embed in frontend code |
JavaScript Integration
Add the Logproof widget to your page with just a few lines of code:
<!-- Container for the widget -->
<div id="logproof-timeline"></div>
<!-- Load the Logproof widget script -->
<script src="https://logproof.de/widget/logproof.js"></script>
<!-- Initialize the widget -->
<script>
LogproofWidget.init({
token: 'lp_wt_1a2b3c4d5e6f7g8h9i0j',
container: '#logproof-timeline',
theme: 'dark',
locale: 'en',
});
</script>
Configuration Options
The LogproofWidget.init() method accepts the following configuration options:
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
token |
string | Yes | - | Your widget token starting with lp_wt_ |
container |
string | Yes | - | CSS selector for the container element |
apiUrl |
string | No | https://logproof.de/v1 |
Custom API base URL |
theme |
string | No | auto |
Widget theme: light, dark, or auto |
locale |
string | No | en |
Language code: en, de |
limit |
number | No | 25 |
Number of events per page (max 50) |
filters |
object | No | {} |
Filter events (see below) |
showActor |
boolean | No | true |
Display actor information |
showTarget |
boolean | No | true |
Display target information |
autoRefresh |
number | No | 0 |
Auto-refresh interval in seconds (0 = disabled) |
Filter Options
The filters object supports the following properties:
filters: {
actor_id: 'user_123',
target_id: 'doc_456',
target_type: 'document'
}
Instance Methods
The init() method returns a widget instance with the following methods:
refresh()
Manually refresh the timeline to fetch the latest events.
const widget = LogproofWidget.init({
token: 'lp_wt_1a2b3c4d5e6f7g8h9i0j',
container: '#logproof-timeline'
});
// Refresh the timeline
widget.refresh();
destroy()
Remove the widget from the DOM and clean up event listeners.
// Clean up the widget widget.destroy();
Advanced Example
Here's a complete example with all configuration options:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Logproof Timeline</title>
<style>
#logproof-timeline {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
</style>
</head>
<body>
<div id="logproof-timeline"></div>
<script src="https://logproof.de/widget/logproof.js"></script>
<script>
const widget = LogproofWidget.init({
token: 'lp_wt_1a2b3c4d5e6f7g8h9i0j',
container: '#logproof-timeline',
theme: 'dark',
locale: 'en',
limit: 50,
filters: {
actor_id: 'user_123',
target_type: 'document'
},
showActor: true,
showTarget: true,
autoRefresh: 30 // Refresh every 30 seconds
});
// Programmatic refresh example
document.querySelector('#refresh-btn')?.addEventListener('click', () => {
widget.refresh();
});
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
widget.destroy();
});
</script>
</body>
</html>
Timeline API Endpoint
https://logproof.de/v1/widget/timeline
The widget uses this endpoint to fetch events. You can also call it directly if you're building a custom interface.
Authentication: Bearer token (widget token)
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
number | No | Number of events to return (default: 25, max: 50) |
cursor |
string | No | Pagination cursor from previous response |
actor_id |
string | No | Filter by actor ID |
target_id |
string | No | Filter by target ID |
target_type |
string | No | Filter by target type |
Example Request
curl -X GET "https://logproof.de/v1/widget/timeline?limit=25&actor_id=user_123" \ -H "Authorization: Bearer lp_wt_1a2b3c4d5e6f7g8h9i0j"
const response = await fetch(
'https://logproof.de/v1/widget/timeline?limit=25&actor_id=user_123',
{
headers: {
'Authorization': 'Bearer lp_wt_1a2b3c4d5e6f7g8h9i0j'
}
}
);
const data = await response.json();
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://logproof.de/v1/widget/timeline',
[
'headers' => [
'Authorization' => 'Bearer lp_wt_1a2b3c4d5e6f7g8h9i0j'
],
'query' => [
'limit' => 25,
'actor_id' => 'user_123'
]
]
);
$data = json_decode($response->getBody(), true);
import requests
response = requests.get(
'https://logproof.de/v1/widget/timeline',
headers={
'Authorization': 'Bearer lp_wt_1a2b3c4d5e6f7g8h9i0j'
},
params={
'limit': 25,
'actor_id': 'user_123'
}
)
data = response.json()
Response Body
{
"data": [
{
"id": "evt_1a2b3c4d5e6f",
"event": "document.updated",
"actor": {
"id": "user_123",
"name": "John Doe",
"email": "john@example.com"
},
"target": {
"id": "doc_456",
"type": "document",
"name": "Project Proposal"
},
"metadata": {
"changes": ["title", "content"]
},
"occurred_at": "2026-02-10T14:30:00Z"
}
],
"pagination": {
"has_more": true,
"next_cursor": "Y3Vyc29yOjEyMzQ1Njc4OTA"
}
}
Customizing Styles
The widget respects your page's CSS and can be styled using custom CSS:
<style>
/* Container styling */
#logproof-timeline {
font-family: 'Inter', sans-serif;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* Override widget theme colors */
.logproof-widget {
--lp-primary-color: #3b82f6;
--lp-background-color: #ffffff;
--lp-text-color: #1f2937;
--lp-border-color: #e5e7eb;
}
/* Dark theme overrides */
.logproof-widget[data-theme="dark"] {
--lp-background-color: #1f2937;
--lp-text-color: #f9fafb;
--lp-border-color: #374151;
}
</style>