> For the complete documentation index, see [llms.txt](https://docs.hackle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hackle.io/en/development-guide/sdk/user-identifier/client-user-identifier.md).

# Client User Identifier

On the client, you can use a User Identifier in two ways.

* Using the device identifier managed internally by the SDK
* Using a custom identifier

## Using the Device Identifier Managed Internally by the SDK

{% hint style="warning" %}
Available only for Client-side SDKs.
{% endhint %}

Client-side SDKs include functionality for managing the device identifier.\
Therefore, users can be automatically identified without passing a separate User Identifier.

For JavaScript, Android, and iOS, you can obtain the device identifier managed by the SDK — refer to the example code below.

```javascript
// Variation distribution
const experimentKey = 42
const variation = hackleClient.variation(experimentKey)

// Event tracking
hackleClient.track("purchase")

// Get the internally managed device identifier
const userId = Hackle.getUserId()
```

```java
// Variation distribution
int experimentKey = 42;
Variation variation = hackleApp.variation(experimentKey);

// Event tracking
hackleApp.track("purchase");

// Get the internally managed device identifier
String deviceId = hackleApp.getDeviceId();
```

```swift
// Variation distribution
let variation = hackleApp.variation(experimentKey: 42)

// Event tracking
hackleApp.track(eventKey: "purchase")

// Get the internally managed device identifier
let deviceId = hackleApp.deviceId
```

```javascript
<HackleProvider hackleClient={hackleClient}>
  <YourApp />
</HackleProvider>
```

## Using a Custom Identifier

The SDK identifies users via the identifier passed as a parameter.\
The identifier you pass can be a Primary Key you manage yourself, a device identifier, a member ID, an email address, a hash value, etc.

```javascript
// Variation distribution
const experimentKey = 42;
const user = { userId: "ae2182e0" };
const variation = hackleClient.variation(experimentKey, user);

// Event tracking
hackleClient.track("purchase", user);
```

```java
// Variation distribution
long experimentKey = 42L;
String userId = "ae2182e0";
Variation variation = hackleApp.variation(experimentKey, userId);

// Event tracking
hackleApp.track("purchase", userId);
```

```swift
// Variation distribution
let variation = hackleApp.variation(experimentKey: 42, userId: "ae2182e0")

// Event tracking
hackleApp.track(eventKey: "purchase", userId: "ae2182e0")
```

```javascript
const user = { 
    userId: "ae2182e0"
}

<HackleProvider hackleClient={hackleClient} user={user}>
  <YourApp />
```

### Example: Creating a Custom Identifier

If you only need data for logged-in users, you can use the member ID or email address used at login as the identifier.

However, if you need to include non-logged-in users, it is recommended to use a value that can distinguish users based on the app, device, or browser.\
(For mobile apps, use a UUID or ADID value; for PC/Mobile web, use a cookie value.)

Below is an example of generating a User Identifier based on cookies.

```javascript
import Cookies from "js-cookie"
import uuid4 from "uuid4"
function getUserId() {
  const key = "PCID" // Enter your preferred name
  const id = Cookies.get(key)
  if (id) {
    return id
  } else {
    const id = uuid4()
    const [top, second] = window.location.hostname.split(".").reverse()
    const domain = `.${second}.${top}`
    Cookies.set(key, id, { expires: 99999, domain: domain, path: "/" })
    return id
  }
}
```

```javascript
const app = require("express")()
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const {v4: uuidv4} = require("uuid")

app.use(bodyParser.urlencoded({extended: false}))
app.use(cookieParser())
app.set("view engine", "ejs")
app.set("views", "views")

function extractDomain(hostname) {
    const DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i;
    const SIMPLE_DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]*\.[a-z]+$/i;
    let domain_regex = DOMAIN_MATCH_REGEX;
    const parts = hostname.split(".");
    const tld = parts[parts.length - 1];
    if (tld.length > 4 || tld === "com" || tld === "org") {
        domain_regex = SIMPLE_DOMAIN_MATCH_REGEX;
    }
    const matches = hostname.match(domain_regex);
    return matches ? matches[0] : "";
}

app.use((req, res, next) => {
    const domain = extractDomain(req.headers.host)

    if (!req.cookies.deviceId) {
        const deviceId = uuidv4()
        res.cookie("deviceId", deviceId, {
            maxAge: 365 * 10 * 365 * 24 * 60 * 60,
            domain: domain,
            path: "/"
        })
        req.cookies.deviceId = deviceId
    }
    next()
});

app.get("/", (req, res) => {
    console.log(req.cookies.deviceId)
    res.render("index")
});

app.listen(3000, () => {
    console.log("App Start")
});
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hackle.io/en/development-guide/sdk/user-identifier/client-user-identifier.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
