Docs

Feed Component

A drop-in Web Component that renders clean, paginated activity feeds anywhere in your product — account settings, team pages, admin views. Built with Angular Elements (zoneless, Shadow DOM), framework-agnostic, ~42 kB gzipped.

Load the script

index.htmlfeed.js
<script src="https://softechlog.com/feed.js"></script>

Mint a feed token on your server

Public keys are ingest-only, so the browser cannot read activity with one. Instead your backend mints a feed token (stl_ft_…) with the secret key: a short-lived, read-only credential pinned to exactly one actor (and optionally one target). Any page holding it can read only that user's activity — nothing else, and never exports or stats.

api/activity-token.tsNode SDK
// GET /api/activity-token — @softechlog/node
const { token, expires_at } = await log.feedToken({
  actorId: req.user.id, // whose activity may be read
  ttlSeconds: 3600,     // 60 – 86400 (default 3600)
  // targetType: "workspace", targetId: workspace.id  // optionally pin to one resource
});
res.json({ token, expires_at });
app/activity.pyPython SDK
# GET /activity-token — softechlog (Python)
@router.get("/activity-token")
async def activity_token(current_user: User = Depends(get_current_user)):
    tok = await log.afeed_token(actor_id=str(current_user.id), ttl_seconds=3600)
    return {"token": tok.token, "expires_at": tok.expires_at}
POST /v1/feed-tokensraw HTTP
POST https://api.softechlog.com/v1/feed-tokens
Authorization: Bearer stl_sk_xxxxxxxxxxxx
Content-Type: application/json

{ "actor_id": "user_123", "ttl_seconds": 3600 }

→ 201 { "token": "stl_ft_…", "expires_at": "2026-08-18T15:09:31Z", "actor_id": "user_123" }

Tokens live 60 seconds to 24 hours (ttl_seconds, default 3600). When one expires the component shows an "expired" error state — fetch a fresh token from your endpoint and set the attribute again.

Usage

Fetch the token from your backend when the page loads, then set the feed-token attribute. Add target-type / target-id to narrow the feed to one resource:

settings.htmlplain HTML
<!-- Everything the signed-in user did -->
<softechlog-feed id="feed"></softechlog-feed>

<script>
  fetch('/api/activity-token')
    .then((r) => r.json())
    .then(({ token }) => document.getElementById('feed').setAttribute('feed-token', token));
</script>

<!-- Only what they did to one resource -->
<softechlog-feed
  feed-token="stl_ft_…"
  target-type="workspace"
  target-id="ws_abc"
></softechlog-feed>

In Angular

settings.component.htmlAngular
<softechlog-feed
  [attr.feed-token]="feedToken"
  theme="auto"
></softechlog-feed>

In React

Settings.jsxReact
<softechlog-feed feed-token={token} theme="auto" />

Attributes

AttributeTypeDefaultDescription
feed-tokenstringrequiredActor-scoped token from POST /v1/feed-tokens
target-typestringOnly events on this resource type
target-idstringOnly events on this resource
themelight · dark · autoautoauto follows prefers-color-scheme
limitnumber25Events per page (max 100)
localestringbrowserLocale for dates and times
empty-textstringNo activity yet.Copy for the empty state
api-urlstringhttps://api.softechlog.comOverride the API base URL

The token already fixes the actor, so there is no actor-id attribute to set — and no attribute can widen the token's scope.

Theming with CSS custom properties

The component renders in Shadow DOM, so your page CSS can't leak in — and its styles can't leak out. Match your design system through custom properties:

styles.cssCSS custom properties
softechlog-feed {
  --stl-accent: #ee6c2f;        /* avatar gradient & interactive colour */
  --stl-bg: #ffffff;            /* card background */
  --stl-text: #0e1a2c;          /* primary text */
  --stl-muted: #94a3b8;         /* secondary / meta text */
  --stl-border: #e2e8f0;        /* border & divider colour */
  --stl-border-radius: 0.75rem; /* outer card corner radius */
  --stl-avatar-size: 32px;      /* avatar circle diameter */
  --stl-font-family: inherit;   /* font stack */
}
Loading skeleton, "Load more" pagination, empty state, and human-readable errors (expired token, network, rate limit) are built in — you don't need to handle them yourself.