GithubHelp home page GithubHelp logo

iamshgulati / loglib-loglib-ui Goto Github PK

View Code? Open in Web Editor NEW

This project forked from loglib/loglib

0.0 0.0 0.0 3.14 MB

Yet another web analytics tool

Home Page: https://loglib-dashboard.vercel.app

License: MIT License

Shell 0.03% JavaScript 1.25% TypeScript 97.33% CSS 1.38%

loglib-loglib-ui's Introduction

LogLib

Yet Another Web Analytics Tool

npm npm bundle size GitHub license GitHub issues GitHub stars

screenshot

screenshot

Loglib is a web analytics tool that can be attached to your app. It's a privacy-first, have beautiful dashbaord and built for js frameworks ecosystem and it's open source.

Why Loglib

  • Why not?
  • No need to deploy it separately. You can easily attach Loglib to your Next js app (more framework support soon), and you can see your website analytics. (despite having 0 visitors)
  • Keep all your data in your existing database, you have the freedom to store your data in your existing db or your choice of db. We currently support prisma and supabase adapters but more supports are on the way.
  • Behold the beauty of your dashboard, powered by Shadcn UI.
  • Privacy-first and GDPR compliant out of the box, with customization options.
  • You can see basic analytics like vercel analytics but also events aren't paid and it's better than...
  • Your mom will be impressed.
  • And more things are on the way.

Adding loglib to Next JS ๐Ÿ”ฅ

Install like every other library

pnpm add @loglib/next

loglib ships with a cli tool that helps you setup your project. You can run the following command to setup your project and watch as the magic unfolds:

pnpm loglib init

To update all the loglib packages in your app, you can run the following command:

pnpm loglib update

this will setup your project with all possible configurations. Refer to the docs for more information.

Other Frameworks / Separate Deployments

  1. clone https://github.com/LogLib/loglib-starter this repo and run pnpm i to install dependencies.
  2. change .env.example to .env and fill in the required env variables
  3. migrate your database with pnpm prisma migrate or pnpm prisma db push
  4. You can now deploy but if you're deploying to platforms other than vercel you need to setup location resolver for your server. Read more
  5. Now go to your project where you want to track and put loglib url in the LOGLIB_URL or NEXT_PUBLIC_LOGLIB_URL env variable.
  6. Install the loglib tracker in pnpm i @loglib/tracker
  7. Follow the instructions in the doc to setup the tracker.

Manual Setup

Next JS

Advanced Usage

Get Started

Next JS With Prisma

  1. Install like every other library
pnpm i @loglib/tracker @loglib/next @loglib/prisma-adapter @loglib/ui
  1. Copy the following schema to your prisma schema file

Relational DB

model WebVisitor {
    id        String   @id @default(cuid())
    data      String   @default("{}")
    createdAt DateTime @default(now()) @map("created_at")
    updatedAt DateTime @updatedAt @map("updated_at")

    Session  WebSession[]
    Pageview WebPageview[]
    WebEvent WebEvent[]

    @@map("web_visitor")
}

model WebSession {
    id          String        @id @default(cuid())
    createdAt   DateTime      @default(now()) @map("created_at")
    updatedAt   DateTime      @updatedAt @map("updated_at")
    referrer    String        @default("")
    queryParams String        @default("") @map("query_params")
    duration    Int           @default(0)
    country     String?
    city        String?
    device      String?
    os          String?
    browser     String?
    language    String?
    visitorId      String        @map("visitor_id")
    Page        WebPageview[]

    Visitor  WebVisitor    @relation(fields: [visitorId], references: [id], onDelete: Cascade)
    WebEvent WebEvent[]

    @@map("web_session")
}

model WebPageview {
    id          String   @id @default(cuid())
    createdAt   DateTime @default(now()) @map("created_at")
    updatedAt   DateTime @updatedAt @map("updated_at")
    page        String
    referrer    String   @default("")
    queryParams String   @default("{}") @map("query_params")
    duration    Int      @default(0)
    sessionId   String   @map("web_session_id")
    visitorId      String   @map("visitor_id")

    Event      WebEvent[]
    WebSession WebSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
    Visitor    WebVisitor    @relation(fields: [visitorId], references: [id], onDelete: Cascade)

    @@map("web_pageview")
}

model WebEvent {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now()) @map("created_at")
    updatedAt DateTime @updatedAt @map("updated_at")
    eventType String   @map("event_type")
    eventName String   @map("event_name")
    payload   String   @default("")
    pageId    String   @map("page_id")
    sessionId String   @map("web_session_id")
    visitorId String   @map("visitor_id")

    Page       WebPageview @relation(fields: [pageId], references: [id], onDelete: Cascade)
    Visitor    WebVisitor     @relation(fields: [visitorId], references: [id], onDelete: Cascade)
    WebSession WebSession  @relation(fields: [sessionId], references: [id], onDelete: Cascade)

    @@map("web_event")
}
  1. Let's setup the server

App Route

create a file app/api/loglib/route.ts

import { createServerRoutes } from "@loglib/next";
import { prismaAdapter } from "@loglib/prisma-adapter";
import { PrismaClient } from "@prisma/client";

const db = new PrismaClient();

export const { POST, GET } = createServerRoutes({
  adapter: prismaAdapter(db),
});

Pages Route

put this code in src/pages/api/loglib.ts

import { createServer } from "@loglib/next";
import { PrismaClient } from "@prisma/client";
import { prismaAdapter } from "@loglib/prisma-adapter";

const prisma = new PrismaClient();

export default createServer({
  adapter: prismaAdapter(prisma),
});

NOTE: If you want to change the default path of loglib server you can add LOGLIB_URL in your environment variables specifying the full path to your loglib server api url.

  1. Let's setup Dashboard to see our analytics. (yeah not ours it's yours)

Create a page somewhere you want to see your dashboard and just export the dashboard component

app/analytics/page.tsx or pages/analytics.tsx

"use client"; // App Route Only

import { Dashboard } from "@loglib/ui";
import "@loglib/ui/dist/index.css";

export default Dashboard;

NOTE: you probably want to protect this route with some kind of authentication. Either by using a middleware or export the dashboard component inside a protected route.

  1. Let's setup the tracker to collect analytics

src/app/layout.tsx

import LogLib from "@loglib/tracker/react";
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <LogLib
          config={
            {
              //  your config here
            }
          }
        />
        {children}
      </body>
    </html>
  );
}

more info on tracker

Next JS With Supabase

  1. Install like every other library
pnpm i @loglib/tracker @loglib/next @loglib/supabase-adapter @loglib/ui
  1. Copy the following to supabase sql editor and run it
create table if not exists
  public.web_visitor (
    id text not null,
    data text not null default '{}'::text,
    created_at timestamp without time zone not null default current_timestamp,
    updated_at timestamp without time zone not null,
    constraint web_visitor_pkey primary key (id)
  ) tablespace pg_default;

create table if not exists
  public.web_session (
    id text not null,
    created_at timestamp with time zone not null,
    updated_at timestamp with time zone not null,
    referrer text not null default ''::text,
    query_params text not null default ''::text,
    duration integer not null default 0,
    country text null,
    city text null,
    device text null,
    os text null,
    browser text null,
    language text null,
    visitor_id text not null,
    constraint web_session_pkey primary key (id),
    constraint web_session_visitor_id_fkey foreign key (visitor_id) references web_visitor (id) on update cascade on delete cascade
  ) tablespace pg_default;

create table if not exists
  public.web_pageview (
    id text not null,
    created_at timestamp without time zone not null default current_timestamp,
    updated_at timestamp without time zone not null,
    page text not null,
    referrer text not null default ''::text,
    query_params text not null default ''::text,
    duration integer not null default 0,
    session_id text not null,
    visitor_id text not null,
    constraint web_page_pkey primary key (id),
    constraint web_pageview_session_id_fkey foreign key (session_id) references web_session (id) on delete cascade,
    constraint web_pageview_visitor_id_fkey foreign key (visitor_id) references web_visitor (id) on delete cascade
  ) tablespace pg_default;

create table if not exists
  public.web_event (
    id text not null,
    created_at timestamp without time zone not null default current_timestamp,
    updated_at timestamp without time zone not null,
    event_type text not null,
    event_name text not null,
    payload text not null default ''::text,
    page_id text not null,
    session_id text not null,
    visitor_id text not null,
    constraint web_event_pkey primary key (id),
    constraint web_event_page_id_fkey foreign key (page_id) references web_pageview (id) on update cascade on delete cascade,
    constraint web_event_session_id_fkey foreign key (session_id) references web_session (id) on delete cascade,
    constraint web_event_visitor_id_fkey foreign key (visitor_id) references web_visitor (id) on update cascade on delete cascade
  ) tablespace pg_default;
  1. Let's setup the server

App Route

create a file app/api/loglib/route.ts

import { createServerRoutes } from "@loglib/next";
import { supabaseAdapter } from "@loglib/supabase-adapter";
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_KEY
);

export const { POST, GET } = createServerRoutes({
  adapter: supabaseAdapter(supabase),
});

NOTE: If you want to change the default path of loglib server you can add LOGLIB_URL in your environment variables specifying the full path to your loglib server api url.

Pages Route

put this code in src/pages/api/loglib.ts

import { createServer } from "@loglib/next";
import { supabaseAdapter } from "@loglib/supabase-adapter";
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_KEY
);

export default createServer({
  adapter: supabaseAdapter(supabase),
});
  1. Let's setup Dashboard to see our analytics. (yeah not ours it's yours)

Create a page somewhere you want to see your dashboard and just export the dashboard component

app/analytics/page.tsx or pages/analytics.tsx

"use client"; // Next 13 Only

import { Dashboard } from "@loglib/ui";
import "@loglib/ui/dist/index.css";

export default Dashboard;

Now you can navigate to this page and see your analytics. But it will be empty because we haven't setup the tracker yet.

NOTE: you probably want to protect this route with some kind of authentication. Either by using a middleware or export the dashboard component inside a protected route.

  1. Let's setup the tracker to collect analytics

App Route src/app/layout.tsx

import LogLib from "@loglib/tracker/react";
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <LogLib
          config={
            {
              //  your config here
            }
          }
        />
        {children}
      </body>
    </html>
  );
}

Pages Route

import "../../styles/globals.css";
import type { AppProps } from "next/app";
import Loglib from "@loglib/tracker/react";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Loglib
        config={
          {
            //  your config here
          }
        }
      />
      <Component {...pageProps}></Component>
    </>
  );
}

more info on tracker


Docs

Basic Concept

Loglib is consist of three things:

  1. Tracker: This component tracks your website's analytics.
  2. Loglib Server: It handles requests without requiring a separate deployment if you already have a backend.
  3. Loglib Dashboard: It offers a beautiful, minimalistic UI to display your analytics.

The idea is that you can integrate a tracker into your website, similar to other analytics tools. However, instead of sending the data to a third-party server or a separately deployed thing like umami (which we love), it is sent to your current server, which can be set up as an endpoint in your Next.js application (other alternatives in the near future). Then, you can utilize a dashboard that is currently built as a React component (again more frameworks soon). You can export this component as page, enabling you to conveniently view and analyze your website analytics.

Loglib Tracker

Next-js

App Route

src/app/layout.tsx

import Loglib from "@loglib/tracker/react";
export default function RootLayout({
  children,
}: {
  children: React.ReactNode,
}) {
  return (
    <html lang="en">
      <body>
        <Loglib
          config={
            {
              //  your config here
            }
          }
        />
        {children}
      </body>
    </html>
  );
}

Page Route

src/pages/_app.tsx

import Loglib from "@loglib/tracker";
export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Loglib config={{}} />
      <Component {...pageProps} />
    </>
  );
}

IMPORTANT: By default the tracker will send data to the loglib server at the current url on route /api/loglib if you need to change that you can put LOGLIB_URL in your environment variables with the full path.

Other Frameworks

if you're not using next js or react you can use the vanilla version of the tracker that works on any framework just call the record function on the entry point of your application here is example for astro.

<script>
  import {record} from '@loglib/tracker-js'; record(
  {
    // your config here
  })
</script>

CDN

To use loglib via the CDN, simply copy the following code into your script tag and replace the host with your deployed version:

Note that if you don't want to collect development logs, you can pass the env parameter as isDev(your way to know if it's development server) ? "dev": "prod".

<head>
  <script>
    const r = window.document.createElement("script");
    r.type = "text/javascript";
    r.async = !0;
    r.src =
      "https://cdn.jsdelivr.net/npm/@loglib/tracker@latest/dist/index.global.js";
    const a = document.getElementsByTagName("script")[0];
    a.parentNode.insertBefore(r, a);
    r.onload = () => {
      loglib.record({ host: "http://localhost:3000" });
    };
  </script>
</head>

Other Methods

If you want to track a specific event, you can use the track method.

import { loglib } from "@loglib/tracker";
export default function page() {
  return (
    <>
      <button onClick={() => loglib.track("search", { term: "iphone" })}>
        Search
      </button>
    </>
  );
}

To identify a visitor, you can use the identify method. this doesn't work unless you have a consent from the visitor. (more on that below)

import { loglib } from "@logLib/tracker";
export default function page() {
  return (
    <>
      <button onClick={() => loglib.identify({ id: "1", name: "Joe Rogan" })}>
        Identify
      </button>
    </>
  );
}

// Identify we know this is hot topic
// Yeah just pass an object you want to identify the visitor with

User Concent

By default, Loglib tries to track visitors using their IP address. But, we know you're smart enough to know relying on IP addresses isn't the most reliable way to identify unique visitors. So, if you want to track better, here's what you can do:

Step 1: Display a fancy cookie message on your website. (we'll leave the design up to you but might provide something in the future)

Step 2: Once your visitors click that "Accept" button, trigger the Loglib consent function. This will use local storage to assign a unique identifier to each of your visitors.

import { loglib } from "@loglib/tracker";
export default function page() {
  return (
    <>
      <button onClick={() => loglib.setConsent("granted")}>Accept</button>
    </>
  );
}

NOTE: If you don't want to show cookie message, but still want to track using visitor consent, you can set the consent to "granted" by default.

import LogLib from "@loglib/tracker/react";
export default function RootLayout({
  children,
}: {
  children: React.ReactNode,
}) {
  return (
    <html lang="en">
      <body>
        <LogLib
          config={{
            consent: "granted",
          }}
        />
        {children}
      </body>
    </html>
  );
}
options type default description
autoTrack boolean false Automatically track click events with onclick handlers and on buttons
consent string "granted" The consent status of the visitor
debug boolean false Enable debug mode
env string "auto" The environment of the tracker
postInterval number 5 The interval to send events to the server

NOTE: currently you can't use loglib server or dashboard in other frameworks other than next js or react but you can attach the dashboard on astro since you can use react in astro and we'll provide astro server soon. And you can always deploy a new next js project separated from your main project and use it as a dashboard and a server. See the example folder for more.

Loglib Server

first you need to setup a database and an adapter for the server to work.

we currently only support prisma and supabase adapters but more adapters are on the way.

See on nextjs with supabase or nextjs with prisma to see how to setup one. Then you need to create a server handler that will handle the requests from the tracker. Also you can see that on the above links.

Resolving User Location from IP

for getting visitor location using their ip you have 3 options:

  1. Deploy it in vercel and that's it!
  2. If you're not deploying it on serverless environment you can setup maxmind using a cli command
pnpm loglib setup:maxmind

this will download the maxmind database and put it in your project root directory under geo folder.

  1. you can also provide a custom implementation for getting the visitor location by passing a function to the getLocation option.
import { createServer } from "@loglib/next";
import { PrismaClient } from "@prisma/client";
import { prismaAdapter } from "@loglib/prisma-adapter";

const db = new PrismaClient();
const POST = Next13({
  adapter: prismaAdapter(db),
  async getLocation(ip) {
    // do your thing
    return {
      city: "city",
      country: "country",
    };
  },
});
  1. You can disable location from being resolved by passing true to the disableLocation option.
import { createServer } from "@loglib/next";
import { PrismaClient } from "@prisma/client";
import { prismaAdapter } from "@loglib/prisma-adapter";

const db = new PrismaClient();

const POST = Next13({
  adapter: prismaAdapter(db),
  disableLocation: true,
});
  1. You can turn on authentication to guard your both api endpoint and dashboard by passing secret to the auth option. Make sure to include this environment variables in your .env file to access your dashboard.

LOGLIB_USERNAME
LOGLIB_PASSWORD LOGLIB_SECRET

//generated by loglib
import { prismaAdapter } from "@loglib/prisma-adapter";
import { createServer } from "@loglib/next";
import { PrismaClient } from "@prisma/client";

const db = new PrismaClient();

export default createServer({
  adapter: prismaAdapter(db),
  auth: { secret: process.env.LOGLIB_SECRET as string },
});

Loglib Dashboard

You can use the loglib dashboard which is react only right now but there is a plan to support more frameworks in the future.

pnpm add @loglib/ui

then export the dashboard wherever you want in your app.

import { Dashboard } from "@loglib/ui";
import "@loglib/ui/dist/index.css";

export default function page() {
  return (
    <>
      <Dashboard />
    </>
  );
}

You probably want to protect the dashboard with some kind of auth check. You can use our custom credential login but you can also use any auth library you want. Here is an example using next auth.

import { Dashboard } from "@loglib/ui";
import "@loglib/ui/dist/index.css";
import { useSession } from "next-auth/client";

export default function page() {
  const [session, loading] = useSession();
  if (loading) return <div>Loading...</div>;
  if (!session) return <div>Access Denied</div>;
  return (
    <>
      <Dashboard />
    </>
  );
}

Updating Loglib

Loglib is always evolving it might not be usual to update libraries in production apps frequently but you might wanna look at loglib a bit different. There will be always new features and fixes so you might wanna update your loglib version from time to time. We'll try to keep the updates as smooth as possible but since we're still in beta there might be breaking changes but we'll try to keep them to a minimum. You can see the changelog for more info.

loglib-loglib-ui's People

Contributors

baydisng13 avatar bekacru avatar github-actions[bot] avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.