diff --git a/docs/platforms/apple/common/configuration/options.mdx b/docs/platforms/apple/common/configuration/options.mdx
index c0a47ce3aea2e..8ff74a6a9d7fe 100644
--- a/docs/platforms/apple/common/configuration/options.mdx
+++ b/docs/platforms/apple/common/configuration/options.mdx
@@ -878,3 +878,45 @@ The Spotlight URL for local development.
This option is only used when is set to `true`.
+
+## Metrics Options
+
+
+
+When enabled, the SDK sends metrics to Sentry. Metrics can be captured using the `SentrySDK.metrics` API, which allows you to send, view and query counters, gauges and distributions.
+
+Learn more in the Metrics documentation.
+
+
+
+
+
+Use this callback to filter or modify metrics before they're sent to Sentry. Return `nil` to drop the metric.
+
+The callback receives a `SentryMetric` struct and must return either a modified metric or `nil` to drop it. Attributes use the `SentryAttributeValue` protocol, so you can assign valid types directly (`String`, `Bool`, `Int`, `Double`, `Float`, or arrays of these types).
+
+```swift
+import Sentry
+
+SentrySDK.start { options in
+ options.dsn = "___PUBLIC_DSN___"
+ // Metrics are enabled by default, no need to set enableMetrics = true
+ options.experimental.beforeSendMetric = { metric in
+ // Create a mutable copy (SentryMetric is a struct)
+ var metric = metric
+
+ // Drop metrics with specific attributes
+ if case .boolean(let dropMe) = metric.attributes["dropMe"], dropMe {
+ return nil
+ }
+
+ // Modify metric attributes using literals
+ metric.attributes["processed"] = true
+ metric.attributes["processed_at"] = "2024-01-01"
+
+ return metric
+ }
+}
+```
+
+
diff --git a/docs/platforms/apple/common/features/experimental-features.mdx b/docs/platforms/apple/common/features/experimental-features.mdx
index e956a01273076..21d56b223e579 100644
--- a/docs/platforms/apple/common/features/experimental-features.mdx
+++ b/docs/platforms/apple/common/features/experimental-features.mdx
@@ -22,5 +22,6 @@ Do you want to try some new experimental features? On the latest version of the
- If you use Swift concurrency, stitch together stack traces of your async code with the `swiftAsyncStacktraces` option. Note that you can enable this in your Objective-C project, but only async code written in Swift will be stitched together.
- Enable the `enablePersistingTracesWhenCrashing` option to link ongoing transactions to a crash event when your app crashes.
- Enable the `enableUnhandledCPPExceptionsV2` option to capture fatal CPPExceptions via hooking into `cxa_throw`
+- Enable Metrics to send counters, gauges, and distributions from your application to track application health and drill down into related traces, logs, and errors.
Let us know if you have feedback through [GitHub issues](https://github.com/getsentry/sentry-cocoa/issues).
diff --git a/docs/platforms/apple/common/metrics/index.mdx b/docs/platforms/apple/common/metrics/index.mdx
new file mode 100644
index 0000000000000..8bc22fce95bc5
--- /dev/null
+++ b/docs/platforms/apple/common/metrics/index.mdx
@@ -0,0 +1,30 @@
+---
+title: Set Up Metrics
+sidebar_title: Metrics
+description: "Metrics allow you to send, view and query counters, gauges, and distributions from your Sentry-configured apps to track application health and drill down into related traces, logs, and errors."
+sidebar_order: 7
+sidebar_section: features
+beta: true
+---
+
+With Sentry Metrics, you can send counters, gauges, and distributions from your applications to Sentry. Once in Sentry, these metrics can be viewed alongside relevant errors, traces, and logs, and searched using their individual attributes.
+
+
+This feature is currently in open beta. Please reach out on [GitHub](https://github.com/getsentry/sentry-cocoa/discussions) if you have feedback or questions. Features in beta are still in-progress and may have bugs. We recognize the irony.
+
+
+## Requirements
+
+
+
+## Usage
+
+
+
+## Options
+
+
+
+## Default Attributes
+
+
diff --git a/platform-includes/metrics/default-attributes/apple.mdx b/platform-includes/metrics/default-attributes/apple.mdx
new file mode 100644
index 0000000000000..152b20cef864f
--- /dev/null
+++ b/platform-includes/metrics/default-attributes/apple.mdx
@@ -0,0 +1,40 @@
+By default the SDK will attach the following attributes to a metric:
+
+### SDK Attributes
+
+- `sentry.sdk.name`: The name of the SDK that sent the metric (e.g., "sentry.cocoa").
+- `sentry.sdk.version`: The version of the SDK that sent the metric.
+- `sentry.environment`: The environment set in the SDK.
+- `sentry.release`: The release set in the SDK, if defined.
+
+### Device and OS Attributes
+
+- `device.brand`: Always "Apple" for Apple devices.
+- `device.model`: The device model (e.g., "iPhone14,2").
+- `device.family`: The device family (e.g., "iPhone").
+- `os.name`: The operating system name (e.g., "iOS").
+- `os.version`: The operating system version.
+
+### User Attributes
+
+User attributes are only added when `options.sendDefaultPii` is set to `true`:
+
+- `user.id`: The user ID from the current scope. Falls back to the installation ID if no user is set.
+- `user.name`: The username from the current scope.
+- `user.email`: The email address from the current scope.
+
+### Trace Attributes
+
+If there is an active span when the metric is recorded, the following attribute is added:
+
+- `span_id`: The span ID of the active span.
+
+
+The `trace_id` is set as a top-level field on the metric (not as an attribute) to enable distributed tracing correlation. When a span is active, the SDK uses that span's trace ID; otherwise, it falls back to the propagation context's trace ID.
+
+
+### Session Replay Attributes
+
+If Session Replay is enabled and active (iOS and tvOS only):
+
+- `sentry.replay_id`: The current replay session ID.
diff --git a/platform-includes/metrics/options/apple.mdx b/platform-includes/metrics/options/apple.mdx
new file mode 100644
index 0000000000000..8753945b43a48
--- /dev/null
+++ b/platform-includes/metrics/options/apple.mdx
@@ -0,0 +1,87 @@
+The Sentry Cocoa SDK provides several options to configure how metrics are captured and sent to Sentry.
+
+### Enabling/Disabling Metrics
+
+Metrics are enabled by default. If you need to disable metrics, set `enableMetrics` to `false` in the experimental options when initializing the SDK:
+
+```swift
+import Sentry
+
+SentrySDK.start { options in
+ options.dsn = "___PUBLIC_DSN___"
+ options.experimental.enableMetrics = false // Metrics are enabled by default
+}
+```
+
+### Filtering and Modifying Metrics
+
+Use the `beforeSendMetric` callback to filter or modify metrics before they're sent to Sentry. This is useful for:
+
+- Removing sensitive data from metric attributes
+- Dropping metrics you don't want to send
+- Adding or modifying attributes
+- Changing metric names or units
+
+The callback receives a `SentryMetric` struct and must return either a modified metric or `nil` to drop it.
+
+**Available `SentryMetric` properties:**
+- `name`: The metric name (e.g., "api.response_time")
+- `value`: The metric value (`SentryMetricValue` - counter, distribution, or gauge)
+- `unit`: The unit of measurement (`SentryUnit?`)
+- `attributes`: Dictionary of attributes (`[String: SentryAttributeContent]`)
+- `timestamp`: When the metric was recorded
+- `traceId`: Associated trace ID for distributed tracing correlation
+
+When modifying `attributes`, you can assign values directly using literals thanks to Swift's `ExpressibleBy...Literal` protocols. The SDK supports `String`, `Bool`, `Int`, `Double`, and arrays of these types.
+
+```swift
+import Sentry
+
+SentrySDK.start { options in
+ options.dsn = "___PUBLIC_DSN___"
+ // Metrics are enabled by default, no need to set enableMetrics = true
+ options.experimental.beforeSendMetric = { metric in
+ // Create a mutable copy (SentryMetric is a struct)
+ var metric = metric
+
+ // Drop metrics based on attributes
+ if case .boolean(let dropMe) = metric.attributes["dropMe"], dropMe {
+ return nil
+ }
+
+ // Drop metrics by name
+ if metric.name.hasPrefix("internal.") {
+ return nil
+ }
+
+ // Modify or add attributes using literals (recommended)
+ metric.attributes["processed"] = true // Boolean literal
+ metric.attributes["environment"] = "production" // String literal
+ metric.attributes["retry_count"] = 3 // Integer literal
+ metric.attributes["latency"] = 42.5 // Double literal
+
+ // You can also use enum cases for explicitness
+ metric.attributes["explicit"] = .boolean(true)
+ metric.attributes["tags"] = .stringArray(["tag1", "tag2"])
+
+ // Change the metric name
+ if metric.name == "legacy_metric" {
+ metric.name = "new_metric_name"
+ }
+
+ return metric
+ }
+}
+```
+
+### Flushing Metrics
+
+By default, metrics are buffered and flushed depending on buffer size and time. If you need to manually flush metrics before the automatic interval, you can use the `flush` method:
+
+```swift
+import Sentry
+
+SentrySDK.flush(timeout: 5.0)
+```
+
+This will flush all pending metrics and events to Sentry.
diff --git a/platform-includes/metrics/requirements/apple.mdx b/platform-includes/metrics/requirements/apple.mdx
new file mode 100644
index 0000000000000..8dd85884cccca
--- /dev/null
+++ b/platform-includes/metrics/requirements/apple.mdx
@@ -0,0 +1 @@
+Metrics are supported in Sentry Cocoa SDK version `9.2.0` and above.
diff --git a/platform-includes/metrics/usage/apple.mdx b/platform-includes/metrics/usage/apple.mdx
new file mode 100644
index 0000000000000..02b971abfcb5a
--- /dev/null
+++ b/platform-includes/metrics/usage/apple.mdx
@@ -0,0 +1,148 @@
+Once the SDK is initialized, you can send metrics using the `SentrySDK.metrics` APIs. Metrics are enabled by default.
+
+The `metrics` namespace exposes three methods that you can use to capture different types of metric information: `count`, `gauge` and `distribution`.
+
+
+Objective-C support for metrics is not currently available. If you need Objective-C support, please [open an issue](https://github.com/getsentry/sentry-cocoa/issues) to show demand for this feature.
+
+
+### Counter
+
+Counters track discrete occurrence counts. Use this to increment or set a count associated with a metric key, such as the number of events, requests, or errors.
+
+**Key characteristics:**
+- Values are typically non-negative integers
+- Use descriptive, lowercase, dot-delimited names (e.g., `"network.request.count"`)
+
+```swift
+import Sentry
+
+// Simple counter
+SentrySDK.metrics.count(key: "button_click", value: 1)
+
+// Counter with unit and attributes
+SentrySDK.metrics.count(
+ key: "network.request.count",
+ value: 1,
+ unit: .generic("request"),
+ attributes: ["endpoint": "/api/users", "method": "POST"]
+)
+```
+
+### Gauge
+
+Gauges track values that can go up and down over time, representing a current state rather than an incrementing counter. Use this for metrics like current memory usage, queue depth, or active connections.
+
+**Key characteristics:**
+- Values can increase or decrease
+- Represents the state at the time of recording
+- Supports aggregates like min, max, avg, sum, and count
+- Cannot be used to calculate percentiles (use distributions for that)
+
+```swift
+import Sentry
+
+// Simple gauge
+SentrySDK.metrics.gauge(key: "queue_depth", value: 42.0)
+
+// Gauge with unit
+SentrySDK.metrics.gauge(
+ key: "memory.usage",
+ value: 1024.0,
+ unit: .megabyte
+)
+```
+
+### Distribution
+
+Distributions track the distribution of a value over time, allowing you to analyze statistical properties like mean, median, and percentiles. Use this for measurable quantities like response times or request durations.
+
+**Key characteristics:**
+- Enables percentile calculations (p50, p90, p99, etc.)
+- Best for analyzing statistical properties of measurements
+- Use for values where you need to understand distribution, not just aggregates
+
+```swift
+import Sentry
+
+// Simple distribution
+SentrySDK.metrics.distribution(key: "response_time", value: 187.5)
+
+// Distribution with unit and attributes
+SentrySDK.metrics.distribution(
+ key: "http.request.duration",
+ value: 187.5,
+ unit: .millisecond,
+ attributes: ["endpoint": "/api/data", "cached": false]
+)
+```
+
+### Adding Attributes
+
+You can also pass additional attributes to any of the metric methods via the `attributes` parameter. Attributes allow you to filter and group metrics.
+
+The SDK uses the `SentryAttributeValue` protocol to provide **compile-time type safety** for attribute values. This means you can pass native Swift types directly without wrapping them, and the compiler will ensure only valid types are accepted.
+
+**Supported attribute types:**
+- **Scalar types**: `String`, `Bool`, `Int`, `Double`, `Float`
+- **Array types**: `[String]`, `[Bool]`, `[Int]`, `[Double]`, `[Float]`
+
+The protocol automatically handles type conversion and validation, so you can use Swift's native types directly in your code. Invalid types will be caught at compile time, preventing runtime errors.
+
+```swift
+import Sentry
+
+SentrySDK.metrics.count(
+ key: "button_click",
+ value: 1,
+ unit: nil,
+ attributes: [
+ "browser": "Firefox", // String - passed directly
+ "app_version": "1.0.0", // String - passed directly
+ "build_number": 123, // Int - passed directly
+ "is_premium": true, // Bool - passed directly
+ "success_rate": 0.95, // Double - passed directly
+ "tags": ["production", "v2"] // [String] - passed directly
+ ]
+)
+```
+
+The `SentryAttributeValue` protocol ensures that all these types are automatically converted to the correct internal representation, providing both type safety and a clean, idiomatic Swift API.
+
+### Specifying Units
+
+All metric types (`count`, `gauge`, and `distribution`) support the optional `unit` parameter. Units help Sentry display metric values in a human-readable format.
+
+The SDK provides the `SentryUnit` enum with type-safe unit values:
+
+```swift
+import Sentry
+
+// Use enum cases for type safety (recommended)
+SentrySDK.metrics.distribution(
+ key: "response_time",
+ value: 187.5,
+ unit: .millisecond
+)
+
+SentrySDK.metrics.gauge(
+ key: "memory_usage",
+ value: 1024.0,
+ unit: .byte
+)
+
+SentrySDK.metrics.distribution(
+ key: "cache_latency",
+ value: 42.3,
+ unit: .microsecond
+)
+```
+
+**Available unit categories:**
+
+- **Duration**: `.nanosecond`, `.microsecond`, `.millisecond`, `.second`, `.minute`, `.hour`, `.day`, `.week`
+- **Information**: `.bit`, `.byte`, `.kilobyte`, `.kibibyte`, `.megabyte`, `.mebibyte`, `.gigabyte`, `.gibibyte`, `.terabyte`, `.tebibyte`, `.petabyte`, `.pebibyte`, `.exabyte`, `.exbibyte`
+- **Fraction**: `.ratio`, `.percent`
+- **Custom**: `.generic("custom_unit")` for any other unit
+
+You can also use string literals (e.g., `unit: "millisecond"`), which are automatically converted to the corresponding enum case. However, using enum cases is recommended for compile-time safety.