or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ai-integrations.mdclient-management.mdcontext-management.mdevent-tracking.mdfeature-flags.mdindex.mduser-group-management.md

user-group-management.mddocs/

0

# User and Group Management

1

2

User identification and property management system for tracking user attributes, behavioral data, and organizational groupings. PostHog's user management supports both individual user properties and group-level data for multi-tenant applications.

3

4

## Capabilities

5

6

### User Property Management

7

8

Set and manage user properties with support for both overwriting and append-only operations.

9

10

```python { .api }

11

def set(**kwargs: OptionalSetArgs) -> Optional[str]:

12

"""

13

Set properties on a user record.

14

15

Parameters:

16

- distinct_id: Optional[ID_TYPES] - Unique identifier for the user (defaults to context user)

17

- properties: Optional[Dict[str, Any]] - Dictionary of properties to set on the user

18

- timestamp: Optional[Union[datetime, str]] - When the properties were set

19

- uuid: Optional[str] - Unique identifier for this operation

20

- disable_geoip: Optional[bool] - Whether to disable GeoIP lookup

21

22

Returns:

23

Optional[str] - The operation UUID if successful

24

25

Notes:

26

- Overwrites existing property values

27

- Context tags are folded into properties

28

- No-op if no distinct_id available

29

"""

30

31

def set_once(**kwargs: OptionalSetArgs) -> Optional[str]:

32

"""

33

Set properties on a user record, only if they do not yet exist.

34

35

Parameters:

36

- Same as set() method

37

38

Returns:

39

Optional[str] - The operation UUID if successful

40

41

Notes:

42

- Does not overwrite existing property values

43

- Otherwise behaves identically to set()

44

"""

45

```

46

47

### Group Management

48

49

Manage group properties and associations for organizational or team-level data tracking.

50

51

```python { .api }

52

def group_identify(

53

group_type: str,

54

group_key: str,

55

properties: Optional[Dict] = None,

56

timestamp: Optional[datetime] = None,

57

uuid: Optional[str] = None,

58

disable_geoip: Optional[bool] = None

59

) -> Optional[str]:

60

"""

61

Set properties on a group.

62

63

Parameters:

64

- group_type: str - Type of your group (e.g., 'company', 'team', 'organization')

65

- group_key: str - Unique identifier of the group

66

- properties: Optional[Dict] - Properties to set on the group

67

- timestamp: Optional[datetime] - When the group was identified

68

- uuid: Optional[str] - Unique identifier for this operation

69

- disable_geoip: Optional[bool] - Whether to disable GeoIP lookup

70

71

Returns:

72

Optional[str] - The operation UUID if successful

73

"""

74

```

75

76

### User Identity Management

77

78

Link user identities across different stages of their lifecycle and associate anonymous behavior with identified users.

79

80

```python { .api }

81

def alias(

82

previous_id: str,

83

distinct_id: str,

84

timestamp: Optional[datetime] = None,

85

uuid: Optional[str] = None,

86

disable_geoip: Optional[bool] = None

87

) -> Optional[str]:

88

"""

89

Associate user behaviour before and after they e.g. register, login, or perform some other identifying action.

90

91

Parameters:

92

- previous_id: str - The unique ID of the user before identification

93

- distinct_id: str - The current unique id after identification

94

- timestamp: Optional[datetime] - When the alias was created

95

- uuid: Optional[str] - Unique identifier for this operation

96

- disable_geoip: Optional[bool] - Whether to disable GeoIP lookup

97

98

Returns:

99

Optional[str] - The operation UUID if successful

100

101

Notes:

102

- Links anonymous behavior to identified users

103

- Enables cohort analysis across user lifecycle

104

- Should be called when user identity becomes known

105

"""

106

```

107

108

## Usage Examples

109

110

### User Property Management

111

112

```python

113

import posthog

114

115

# Configure PostHog

116

posthog.api_key = 'phc_your_project_api_key'

117

118

# Set user properties (overwrites existing)

119

posthog.set('user123', {

120

'email': 'user@example.com',

121

'name': 'John Doe',

122

'plan': 'premium',

123

'signup_date': '2024-01-15',

124

'trial_end': '2024-02-15'

125

})

126

127

# Set properties only if they don't exist

128

posthog.set_once('user123', {

129

'first_visit': '2024-01-10',

130

'initial_referrer': 'google.com',

131

'signup_source': 'landing_page'

132

})

133

134

# Using context for automatic user identification

135

with posthog.new_context():

136

posthog.identify_context('user123')

137

138

# User ID automatically applied from context

139

posthog.set({

140

'last_active': '2024-09-07',

141

'feature_usage_count': 42

142

})

143

```

144

145

### Group Management

146

147

```python

148

import posthog

149

150

# Identify a company/organization

151

posthog.group_identify('company', 'acme_corp', {

152

'name': 'Acme Corporation',

153

'industry': 'Technology',

154

'size': 'Enterprise',

155

'plan': 'Business',

156

'mrr': 5000,

157

'employees': 250

158

})

159

160

# Identify a team within organization

161

posthog.group_identify('team', 'engineering', {

162

'name': 'Engineering Team',

163

'department': 'Product',

164

'lead': 'jane.doe@acme.com',

165

'members_count': 12

166

})

167

168

# Update group properties

169

posthog.group_identify('company', 'acme_corp', {

170

'mrr': 5500, # Updated MRR

171

'employees': 275 # Updated employee count

172

})

173

```

174

175

### User Identity Linking

176

177

```python

178

import posthog

179

180

# User starts as anonymous visitor

181

anonymous_id = 'anonymous_user_abc123'

182

posthog.capture(anonymous_id, 'page_viewed', {'page': 'landing'})

183

posthog.capture(anonymous_id, 'signup_started')

184

185

# User completes registration

186

identified_id = 'user_456'

187

posthog.capture(identified_id, 'signup_completed', {

188

'email': 'user@example.com'

189

})

190

191

# Link anonymous behavior to identified user

192

posthog.alias(anonymous_id, identified_id)

193

194

# Set user properties after identification

195

posthog.set(identified_id, {

196

'email': 'user@example.com',

197

'plan': 'free',

198

'verified': True

199

})

200

```

201

202

### Combined User and Group Tracking

203

204

```python

205

import posthog

206

207

# Set up user with group associations

208

user_id = 'user_789'

209

company_id = 'company_xyz'

210

team_id = 'team_frontend'

211

212

# Identify user properties

213

posthog.set(user_id, {

214

'name': 'Alice Smith',

215

'role': 'Senior Developer',

216

'department': 'Engineering',

217

'hire_date': '2023-06-01'

218

})

219

220

# Identify company

221

posthog.group_identify('company', company_id, {

222

'name': 'XYZ Startup',

223

'industry': 'SaaS',

224

'size': 'Series A',

225

'location': 'San Francisco'

226

})

227

228

# Identify team

229

posthog.group_identify('team', team_id, {

230

'name': 'Frontend Team',

231

'tech_stack': 'React',

232

'team_lead': 'bob.johnson@xyz.com'

233

})

234

235

# Track events with group context

236

posthog.capture(user_id, 'feature_used', {

237

'feature': 'advanced_dashboard'

238

}, groups={

239

'company': company_id,

240

'team': team_id

241

})

242

```

243

244

### Context-Based Property Management

245

246

```python

247

import posthog

248

249

with posthog.new_context():

250

posthog.identify_context('user_456')

251

posthog.tag('session_type', 'premium')

252

posthog.tag('ab_test_group', 'variant_b')

253

254

# Tags are automatically included in user properties

255

posthog.set({

256

'last_login': '2024-09-07T10:30:00Z',

257

'subscription_status': 'active'

258

})

259

260

# Context tags become part of the user profile

261

posthog.capture('dashboard_viewed')

262

```

263

264

## Property Types and Best Practices

265

266

### Supported Property Types

267

268

```python

269

# Strings

270

posthog.set('user123', {'name': 'John Doe', 'plan': 'premium'})

271

272

# Numbers

273

posthog.set('user123', {'age': 28, 'score': 95.5})

274

275

# Booleans

276

posthog.set('user123', {'verified': True, 'trial_expired': False})

277

278

# Dates (as ISO strings)

279

posthog.set('user123', {

280

'signup_date': '2024-01-15T10:30:00Z',

281

'last_active': '2024-09-07'

282

})

283

284

# Arrays

285

posthog.set('user123', {

286

'interests': ['technology', 'sports', 'music'],

287

'visited_pages': ['/home', '/about', '/contact']

288

})

289

```

290

291

### Property Naming Conventions

292

293

```python

294

# Good - clear, consistent naming

295

posthog.set('user123', {

296

'email': 'user@example.com',

297

'first_name': 'John',

298

'last_name': 'Doe',

299

'signup_date': '2024-01-15',

300

'subscription_tier': 'premium',

301

'feature_flags_enabled': ['new_ui', 'beta_features']

302

})

303

304

# Avoid - inconsistent or unclear names

305

posthog.set('user123', {

306

'Email': 'user@example.com', # Inconsistent case

307

'fName': 'John', # Abbreviated

308

'user_registered': '2024-01-15', # Inconsistent naming

309

'tier': 'premium' # Could be ambiguous

310

})

311

```

312

313

### Group Association Patterns

314

315

```python

316

# Multi-level organization structure

317

posthog.capture('user123', 'report_generated', {

318

'report_type': 'monthly_summary'

319

}, groups={

320

'company': 'acme_corp',

321

'division': 'north_america',

322

'team': 'sales_team_west'

323

})

324

325

# Feature flag evaluation with groups

326

enabled = posthog.feature_enabled(

327

'new_dashboard',

328

'user123',

329

groups={'company': 'acme_corp'},

330

person_properties={'plan': 'enterprise'},

331

group_properties={

332

'company': {'size': 'large', 'industry': 'tech'}

333

}

334

)

335

```

336

337

## Error Handling

338

339

### Validation and Fallbacks

340

341

```python

342

# Properties are automatically validated

343

posthog.set('user123', {

344

'valid_string': 'hello',

345

'valid_number': 42,

346

'invalid_function': lambda x: x, # Dropped - not serializable

347

'nested_object': {'key': 'value'} # Flattened automatically

348

})

349

350

# Automatic fallback for missing distinct_id

351

with posthog.new_context():

352

# No context user set - operation is no-op

353

posthog.set({'property': 'value'}) # Does nothing

354

355

posthog.identify_context('user123')

356

posthog.set({'property': 'value'}) # Works correctly

357

```

358

359

### Retry and Reliability

360

361

User and group operations support the same retry mechanisms as events:

362

363

- Automatic retries for network failures

364

- Exponential backoff for rate limits

365

- Queueing for offline scenarios

366

- Error logging for debugging