diff --git a/apps/public/components/common-sdk-config.mdx b/apps/public/components/common-sdk-config.mdx
index 123e7962..20b2732c 100644
--- a/apps/public/components/common-sdk-config.mdx
+++ b/apps/public/components/common-sdk-config.mdx
@@ -5,4 +5,3 @@
- `clientSecret` - The client secret of your application (**only required for server-side events**)
- `filter` - A function that will be called before sending an event. If it returns false, the event will not be sent
- `disabled` - If true, the library will not send any events
-- `waitForProfile` - If true, the library will wait for the profile to be set before sending events
diff --git a/apps/public/content/docs/sdks/astro.mdx b/apps/public/content/docs/sdks/astro.mdx
index 71276cde..19534ed9 100644
--- a/apps/public/content/docs/sdks/astro.mdx
+++ b/apps/public/content/docs/sdks/astro.mdx
@@ -2,4 +2,132 @@
title: Astro
---
-You can use [script tag](/docs/sdks/script) or [Web SDK](/docs/sdks/web) to track events in Astro.
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+import CommonSdkConfig from '@/components/common-sdk-config.mdx';
+import WebSdkConfig from '@/components/web-sdk-config.mdx';
+
+## Installation
+
+
+### Install dependencies
+
+```bash
+pnpm install @openpanel/astro
+```
+
+### Initialize
+
+Add `OpenPanelComponent` to your root layout component.
+
+```astro
+---
+import { OpenPanelComponent } from '@openpanel/astro';
+---
+
+
+
+
+
+
+
+
+
+```
+
+#### Options
+
+
+
+
+##### Astro options
+
+- `profileId` - If you have a user id, you can pass it here to identify the user
+- `cdnUrl` - The url to the OpenPanel SDK (default: `https://openpanel.dev/op1.js`)
+- `filter` - This is a function that will be called before tracking an event. If it returns false the event will not be tracked. [Read more](#filter)
+- `globalProperties` - This is an object of properties that will be sent with every event.
+
+##### `filter`
+
+This options needs to be a stringified function and cannot access any variables outside of the function.
+
+```astro
+
+```
+
+To take advantage of typescript you can do the following. _Note `toString`_
+```ts
+import { type TrackHandlerPayload } from '@openpanel/astro';
+
+const opFilter = ((event: TrackHandlerPayload) => {
+ return event.type === 'track' && event.payload.name === 'my_event';
+}).toString();
+
+
+```
+
+
+
+## Usage
+
+### Client-side Tracking
+
+You can track events with the global op function or you can use data attributes.
+
+```astro
+
+
+```
+
+### Identifying Users
+
+To identify a user, you can use either the `identify` function or the `IdentifyComponent`.
+
+```astro
+---
+import { IdentifyComponent } from '@openpanel/astro';
+---
+
+
+```
+
+### Setting Global Properties
+
+You can set global properties that will be sent with every event using either the `setGlobalProperties` function or the `SetGlobalPropertiesComponent`.
+
+```astro
+---
+import { SetGlobalPropertiesComponent } from '@openpanel/astro';
+---
+
+
+```
\ No newline at end of file
diff --git a/packages/sdks/astro/README.md b/packages/sdks/astro/README.md
new file mode 100644
index 00000000..376e0e3d
--- /dev/null
+++ b/packages/sdks/astro/README.md
@@ -0,0 +1,3 @@
+# OpenPanel Astro SDK
+
+Read full documentation [here](https://openpanel.dev/docs/sdks/astro)
\ No newline at end of file
diff --git a/packages/sdks/astro/env.d.ts b/packages/sdks/astro/env.d.ts
new file mode 100644
index 00000000..57e3c0e7
--- /dev/null
+++ b/packages/sdks/astro/env.d.ts
@@ -0,0 +1,7 @@
+declare module '*.astro' {
+ import type { AstroComponentFactory } from 'astro';
+ const component: AstroComponentFactory;
+ export default component;
+}
+
+///
diff --git a/packages/sdks/astro/index.ts b/packages/sdks/astro/index.ts
new file mode 100644
index 00000000..8bf2b0a2
--- /dev/null
+++ b/packages/sdks/astro/index.ts
@@ -0,0 +1,46 @@
+import type {
+ DecrementPayload,
+ IdentifyPayload,
+ IncrementPayload,
+ TrackProperties,
+} from '@openpanel/web';
+import IdentifyComponent from './src/IdentifyComponent.astro';
+import OpenPanelComponent from './src/OpenPanelComponent.astro';
+import SetGlobalPropertiesComponent from './src/SetGlobalPropertiesComponent.astro';
+
+export * from '@openpanel/web';
+
+export { OpenPanelComponent, IdentifyComponent, SetGlobalPropertiesComponent };
+
+export function setGlobalProperties(properties: Record) {
+ window.op?.('setGlobalProperties', properties);
+}
+
+export function track(name: string, properties?: TrackProperties) {
+ window.op?.('track', name, properties);
+}
+
+export function screenView(properties?: TrackProperties): void;
+export function screenView(path: string, properties?: TrackProperties): void;
+export function screenView(
+ pathOrProperties?: string | TrackProperties,
+ propertiesOrUndefined?: TrackProperties,
+) {
+ window.op?.('screenView', pathOrProperties, propertiesOrUndefined);
+}
+
+export function identify(payload: IdentifyPayload) {
+ window.op?.('identify', payload);
+}
+
+export function increment(payload: IncrementPayload) {
+ window.op?.('increment', payload);
+}
+
+export function decrement(payload: DecrementPayload) {
+ window.op('decrement', payload);
+}
+
+export function clear() {
+ window.op?.('clear');
+}
diff --git a/packages/sdks/astro/package.json b/packages/sdks/astro/package.json
new file mode 100644
index 00000000..4ea86a08
--- /dev/null
+++ b/packages/sdks/astro/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "@openpanel/astro",
+ "version": "1.0.1-local",
+ "config": {
+ "transformPackageJson": false,
+ "transformEnvs": true
+ },
+ "exports": {
+ ".": "./index.ts"
+ },
+ "scripts": {
+ "typecheck": "tsc --noEmit"
+ },
+ "files": ["src", "index.ts"],
+ "keywords": ["astro-component"],
+ "dependencies": {
+ "@openpanel/web": "workspace:1.0.1-local"
+ },
+ "devDependencies": {
+ "astro": "^5.7.7"
+ },
+ "peerDependencies": {
+ "astro": "^4.0.0 || ^5.0.0"
+ },
+ "private": false,
+ "type": "module"
+}
diff --git a/packages/sdks/astro/src/IdentifyComponent.astro b/packages/sdks/astro/src/IdentifyComponent.astro
new file mode 100644
index 00000000..180002db
--- /dev/null
+++ b/packages/sdks/astro/src/IdentifyComponent.astro
@@ -0,0 +1,9 @@
+---
+import type { IdentifyPayload } from '@openpanel/web';
+import { filterProps } from './asto-utils';
+interface Props extends IdentifyPayload {}
+
+const props = Astro.props as Props;
+---
+
+
\ No newline at end of file
diff --git a/packages/sdks/astro/src/OpenPanelComponent.astro b/packages/sdks/astro/src/OpenPanelComponent.astro
new file mode 100644
index 00000000..e982f916
--- /dev/null
+++ b/packages/sdks/astro/src/OpenPanelComponent.astro
@@ -0,0 +1,66 @@
+---
+import type {
+OpenPanelMethodNames,
+OpenPanelOptions
+} from '@openpanel/web';
+
+type Props = Omit & {
+ profileId?: string;
+ cdnUrl?: string;
+ filter?: string;
+ globalProperties?: Record;
+};
+
+const { profileId, cdnUrl, globalProperties, ...options } = Astro.props;
+
+const CDN_URL = 'https://openpanel.dev/op1.js';
+
+const stringify = (obj: unknown) => {
+ if (typeof obj === 'object' && obj !== null && obj !== undefined) {
+ const entries = Object.entries(obj).map(([key, value]) => {
+ if (key === 'filter') {
+ return `"${key}":${value}`;
+ }
+ return `"${key}":${JSON.stringify(value)}`;
+ });
+ return `{${entries.join(',')}}`;
+ }
+
+ return JSON.stringify(obj);
+};
+
+const methods: { name: OpenPanelMethodNames; value: unknown }[] = [
+ {
+ name: 'init',
+ value: {
+ ...options,
+ sdk: 'astro',
+ sdkVersion: '1.0.1',
+ },
+ },
+];
+if (profileId) {
+ methods.push({
+ name: 'identify',
+ value: {
+ profileId,
+ },
+ });
+}
+if (globalProperties) {
+ methods.push({
+ name: 'setGlobalProperties',
+ value: globalProperties,
+ });
+}
+
+const scriptContent = `window.op = window.op || function(...args) {(window.op.q = window.op.q || []).push(args)};
+${methods
+ .map((method) => {
+ return `window.op('${method.name}', ${stringify(method.value)});`;
+ })
+ .join('\n')}`;
+---
+
+
+
\ No newline at end of file
diff --git a/packages/sdks/astro/src/SetGlobalPropertiesComponent.astro b/packages/sdks/astro/src/SetGlobalPropertiesComponent.astro
new file mode 100644
index 00000000..90eb25f4
--- /dev/null
+++ b/packages/sdks/astro/src/SetGlobalPropertiesComponent.astro
@@ -0,0 +1,9 @@
+---
+import { filterProps } from './asto-utils';
+
+type Props = Record;
+
+const props = Astro.props as Props;
+---
+
+
\ No newline at end of file
diff --git a/packages/sdks/astro/src/asto-utils.ts b/packages/sdks/astro/src/asto-utils.ts
new file mode 100644
index 00000000..1b3e1419
--- /dev/null
+++ b/packages/sdks/astro/src/asto-utils.ts
@@ -0,0 +1,7 @@
+const BLACKLISTED_PROPS = ['class'];
+
+export function filterProps(props: Record) {
+ return Object.fromEntries(
+ Object.entries(props).filter(([key]) => !BLACKLISTED_PROPS.includes(key)),
+ );
+}
diff --git a/packages/sdks/astro/tsconfig.json b/packages/sdks/astro/tsconfig.json
new file mode 100644
index 00000000..ae9c58ac
--- /dev/null
+++ b/packages/sdks/astro/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "plugins": [
+ {
+ "name": "@astrojs/ts-plugin"
+ }
+ ],
+ "include": [".astro/types.d.ts", "**/*"],
+ "exclude": ["dist"],
+ "compilerOptions": {
+ "jsx": "preserve"
+ }
+}
diff --git a/packages/sdks/nextjs/index.tsx b/packages/sdks/nextjs/index.tsx
index 97d77d25..d1917ec1 100644
--- a/packages/sdks/nextjs/index.tsx
+++ b/packages/sdks/nextjs/index.tsx
@@ -71,6 +71,7 @@ export function OpenPanelComponent({
<>