clarity-api 0.0.2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clarity_api/__init__.py +19 -0
- clarity_api/clarity_api.py +107 -0
- clarity_api/clarity_models.py +170 -0
- clarity_api/decorators.py +24 -0
- clarity_api/exceptions.py +42 -0
- clarity_api/utils.py +46 -0
- clarity_api/version.py +6 -0
- clarity_api-0.0.2.dist-info/LICENSE +20 -0
- clarity_api-0.0.2.dist-info/METADATA +151 -0
- clarity_api-0.0.2.dist-info/RECORD +12 -0
- clarity_api-0.0.2.dist-info/WHEEL +6 -0
- clarity_api-0.0.2.dist-info/top_level.txt +1 -0
clarity_api/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
from clarity_api.version import __version__, __author__, __credits__
|
|
4
|
+
from clarity_api.clarity_api import Api
|
|
5
|
+
from clarity_api.clarity_models import InputModel, Response
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Clarity API
|
|
9
|
+
|
|
10
|
+
A Python Library for Exporting Data from Microsoft Clarity
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = __version__
|
|
14
|
+
__author__ = __author__
|
|
15
|
+
__credits__ = __credits__
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Api",
|
|
19
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
import urllib3
|
|
6
|
+
from typing import Union
|
|
7
|
+
from pydantic import ValidationError
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from clarity_api.clarity_models import InputModel, Response
|
|
11
|
+
except ModuleNotFoundError:
|
|
12
|
+
from clarity_models import InputModel, Response
|
|
13
|
+
try:
|
|
14
|
+
from clarity_api.decorators import require_auth
|
|
15
|
+
except ModuleNotFoundError:
|
|
16
|
+
from decorators import require_auth
|
|
17
|
+
try:
|
|
18
|
+
from clarity_api.exceptions import (
|
|
19
|
+
AuthError,
|
|
20
|
+
UnauthorizedError,
|
|
21
|
+
ParameterError,
|
|
22
|
+
MissingParameterError,
|
|
23
|
+
)
|
|
24
|
+
except ModuleNotFoundError:
|
|
25
|
+
from exceptions import (
|
|
26
|
+
AuthError,
|
|
27
|
+
UnauthorizedError,
|
|
28
|
+
ParameterError,
|
|
29
|
+
MissingParameterError,
|
|
30
|
+
)
|
|
31
|
+
try:
|
|
32
|
+
from clarity_api.utils import process_response
|
|
33
|
+
except ModuleNotFoundError:
|
|
34
|
+
from utils import process_response
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Api(object):
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
url: str = None,
|
|
42
|
+
token: str = None,
|
|
43
|
+
verify: bool = True,
|
|
44
|
+
):
|
|
45
|
+
if url is None:
|
|
46
|
+
raise MissingParameterError
|
|
47
|
+
|
|
48
|
+
self._session = requests.Session()
|
|
49
|
+
self.url = url
|
|
50
|
+
self.headers = None
|
|
51
|
+
self.verify = verify
|
|
52
|
+
|
|
53
|
+
if self.verify is False:
|
|
54
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
55
|
+
|
|
56
|
+
if token:
|
|
57
|
+
self.headers = {
|
|
58
|
+
"Authorization": f"Bearer {token}",
|
|
59
|
+
"Content-Type": "application/json",
|
|
60
|
+
}
|
|
61
|
+
else:
|
|
62
|
+
raise MissingParameterError
|
|
63
|
+
|
|
64
|
+
response = self._session.get(
|
|
65
|
+
url=f"{self.url}/projects", headers=self.headers, verify=self.verify
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if response.status_code == 403:
|
|
69
|
+
print(f"Unauthorized Error: {response.content}")
|
|
70
|
+
raise UnauthorizedError
|
|
71
|
+
elif response.status_code == 401:
|
|
72
|
+
print(f"Authentication Error: {response.content}")
|
|
73
|
+
raise AuthError
|
|
74
|
+
elif response.status_code == 404:
|
|
75
|
+
print(f"Parameter Error: {response.content}")
|
|
76
|
+
raise ParameterError
|
|
77
|
+
|
|
78
|
+
####################################################################################################################
|
|
79
|
+
# Data Export API #
|
|
80
|
+
####################################################################################################################
|
|
81
|
+
@require_auth
|
|
82
|
+
def get_data_export(self, **kwargs) -> Union[Response, requests.Response]:
|
|
83
|
+
"""
|
|
84
|
+
Retrieve data insights for a project
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
**kwargs: Additional keyword arguments to initialize the BranchModel.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Response: The response object from the GET request.
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ParameterError: If the provided parameters are invalid based on the BranchModel.
|
|
94
|
+
"""
|
|
95
|
+
input_model = InputModel(**kwargs)
|
|
96
|
+
try:
|
|
97
|
+
response = self._session.get(
|
|
98
|
+
url=f"{self.url}/export-data/api/v1/project-live-insights",
|
|
99
|
+
params=input_model.api_parameters,
|
|
100
|
+
headers=self.headers,
|
|
101
|
+
verify=self.verify,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
except ValidationError as e:
|
|
105
|
+
raise ParameterError(f"Invalid parameters: {e.errors()}")
|
|
106
|
+
response = process_response(response=response)
|
|
107
|
+
return response
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from typing import Union, Dict, Optional, Any, List
|
|
6
|
+
from pydantic import (
|
|
7
|
+
BaseModel,
|
|
8
|
+
ConfigDict,
|
|
9
|
+
AliasChoices,
|
|
10
|
+
Field,
|
|
11
|
+
field_validator,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from clarity_api.decorators import require_auth
|
|
16
|
+
except ModuleNotFoundError:
|
|
17
|
+
pass
|
|
18
|
+
try:
|
|
19
|
+
from clarity_api.exceptions import (
|
|
20
|
+
AuthError,
|
|
21
|
+
UnauthorizedError,
|
|
22
|
+
ParameterError,
|
|
23
|
+
MissingParameterError,
|
|
24
|
+
)
|
|
25
|
+
except ModuleNotFoundError:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
logging.basicConfig(
|
|
29
|
+
level=logging.ERROR, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class InputModel(BaseModel):
|
|
34
|
+
"""
|
|
35
|
+
Pydantic model representing information about a branch.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
numOfDays (Union[int, str]): The number of days to return.
|
|
39
|
+
dimension1 (str, optional): The first dimension parameters.
|
|
40
|
+
dimension2 (str, optional): The second dimension parameters.
|
|
41
|
+
dimension3 (str, optional): The third dimension parameters.
|
|
42
|
+
api_parameters (str): Additional API parameters for the group.
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
model_config = ConfigDict(extra="forbid", validate_assignment=True)
|
|
47
|
+
|
|
48
|
+
numOfDays: Optional[Union[int, str]] = Field(
|
|
49
|
+
description="Number of days to save",
|
|
50
|
+
validation_alias=AliasChoices("numOfDays", "number_of_days"),
|
|
51
|
+
default=None,
|
|
52
|
+
)
|
|
53
|
+
dimension1: Optional[str] = Field(
|
|
54
|
+
description="Dimension 1",
|
|
55
|
+
validation_alias=AliasChoices("dimension1", "dimension_1"),
|
|
56
|
+
default=None,
|
|
57
|
+
)
|
|
58
|
+
dimension2: Optional[str] = Field(
|
|
59
|
+
description="Dimension 2",
|
|
60
|
+
validation_alias=AliasChoices("dimension2", "dimension_2"),
|
|
61
|
+
default=None,
|
|
62
|
+
)
|
|
63
|
+
dimension3: Optional[str] = Field(
|
|
64
|
+
description="Dimension 3",
|
|
65
|
+
validation_alias=AliasChoices("dimension3", "dimension_3"),
|
|
66
|
+
default=None,
|
|
67
|
+
)
|
|
68
|
+
api_parameters: Optional[Dict] = Field(description="API Parameters", default=None)
|
|
69
|
+
|
|
70
|
+
def model_post_init(self, __context):
|
|
71
|
+
"""
|
|
72
|
+
Build the API parameters
|
|
73
|
+
"""
|
|
74
|
+
self.api_parameters = {}
|
|
75
|
+
if self.numOfDays:
|
|
76
|
+
self.api_parameters["numOfDays"] = self.numOfDays
|
|
77
|
+
if self.dimension1:
|
|
78
|
+
self.api_parameters["dimension1"] = self.dimension1
|
|
79
|
+
if self.dimension2:
|
|
80
|
+
self.api_parameters["dimension2"] = self.dimension2
|
|
81
|
+
if self.dimension3:
|
|
82
|
+
self.api_parameters["dimension3"] = self.dimension3
|
|
83
|
+
|
|
84
|
+
@field_validator("numOfDays", mode="before")
|
|
85
|
+
def validate_number_of_days(cls, v):
|
|
86
|
+
"""
|
|
87
|
+
Validate the 'number_of_days' parameter to ensure it is a valid integer.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
- v: The value of 'number_of_days'.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
- int: The validated 'number_of_days'.
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
- ParameterError: If 'number_of_days' is not a valid integer.
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
v = int(v)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
raise e
|
|
102
|
+
return v
|
|
103
|
+
|
|
104
|
+
@field_validator("dimension1", "dimension2", "dimension3", mode="before")
|
|
105
|
+
def validate_dimensions(cls, v):
|
|
106
|
+
"""
|
|
107
|
+
Validate the 'dimensions' parameter to ensure it is a valid option.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
- v: The value of 'dimensions'.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
- str: The validated 'dimensions'.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
- ParameterError: If 'dimensions' is not a valid option.
|
|
117
|
+
"""
|
|
118
|
+
if v:
|
|
119
|
+
valid_dimensions = {
|
|
120
|
+
"browser": "Browser",
|
|
121
|
+
"device": "Device",
|
|
122
|
+
"country": "Country",
|
|
123
|
+
"os": "OS",
|
|
124
|
+
"source": "Source",
|
|
125
|
+
"medium": "Medium",
|
|
126
|
+
"campaign": "Campaign",
|
|
127
|
+
"channel": "Channel",
|
|
128
|
+
"url": "URL",
|
|
129
|
+
}
|
|
130
|
+
try:
|
|
131
|
+
return valid_dimensions[v.lower()]
|
|
132
|
+
except KeyError:
|
|
133
|
+
raise ValueError("Invalid dimension")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class Information(BaseModel):
|
|
137
|
+
model_config = ConfigDict(extra="allow")
|
|
138
|
+
totalSessionCount: str = Field(
|
|
139
|
+
default=None, description="The total number of sessions."
|
|
140
|
+
)
|
|
141
|
+
totalBotSessionCount: str = Field(
|
|
142
|
+
default=None, description="The total number of bot sessions."
|
|
143
|
+
)
|
|
144
|
+
distantUserCount: str = Field(default=None, description="The distant user count.")
|
|
145
|
+
PagesPerSessionPercentage: float = Field(
|
|
146
|
+
default=None, description="The pages per session percentage."
|
|
147
|
+
)
|
|
148
|
+
OS: str = Field(default=None, description="The operating system.")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class Metric(BaseModel):
|
|
152
|
+
model_config = ConfigDict(extra="allow")
|
|
153
|
+
metricName: str = Field(
|
|
154
|
+
default=None, description="The name of the returned metric."
|
|
155
|
+
)
|
|
156
|
+
information: List[Information] = Field(
|
|
157
|
+
default=None, description="Result containing available responses."
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Response(BaseModel):
|
|
162
|
+
data: Optional[List[Metric]] = Field(default=None, description="Metrics returned.")
|
|
163
|
+
error: Optional[Any] = Field(default=None, description="Response error code")
|
|
164
|
+
status_code: Union[str, int] = Field(
|
|
165
|
+
default=None, description="Response status code"
|
|
166
|
+
)
|
|
167
|
+
json_output: Optional[Union[List, Dict]] = Field(
|
|
168
|
+
default=None, description="Response JSON data"
|
|
169
|
+
)
|
|
170
|
+
raw_output: Optional[bytes] = Field(default=None, description="Response Raw bytes")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
|
|
4
|
+
import functools
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from clarity_api.exceptions import LoginRequiredError
|
|
8
|
+
except ModuleNotFoundError:
|
|
9
|
+
from exceptions import LoginRequiredError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def require_auth(function):
|
|
13
|
+
"""
|
|
14
|
+
Wraps API calls in function that ensures headers are passed
|
|
15
|
+
with a token
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
@functools.wraps(function)
|
|
19
|
+
def wrapper(self, *args, **kwargs):
|
|
20
|
+
if not self.headers:
|
|
21
|
+
raise LoginRequiredError
|
|
22
|
+
return function(self, *args, **kwargs)
|
|
23
|
+
|
|
24
|
+
return wrapper
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AuthError(Exception):
|
|
6
|
+
"""
|
|
7
|
+
Authentication error
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UnauthorizedError(AuthError):
|
|
14
|
+
"""
|
|
15
|
+
Unauthorized error
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MissingParameterError(Exception):
|
|
22
|
+
"""
|
|
23
|
+
Missing Parameter error
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ParameterError(Exception):
|
|
30
|
+
"""
|
|
31
|
+
Parameter error
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class LoginRequiredError(Exception):
|
|
38
|
+
"""
|
|
39
|
+
Authentication error
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
pass
|
clarity_api/utils.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from clarity_api.clarity_models import (
|
|
10
|
+
Response,
|
|
11
|
+
)
|
|
12
|
+
except ModuleNotFoundError:
|
|
13
|
+
from clarity_models import (
|
|
14
|
+
Response,
|
|
15
|
+
)
|
|
16
|
+
logging.basicConfig(
|
|
17
|
+
level=logging.ERROR, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def process_response(response: requests.Response) -> Union[Response, requests.Response]:
|
|
22
|
+
response_error = None
|
|
23
|
+
try:
|
|
24
|
+
response.raise_for_status()
|
|
25
|
+
except Exception as response_error:
|
|
26
|
+
logging.error(f"Response Error: {response_error}")
|
|
27
|
+
status_code = response.status_code
|
|
28
|
+
raw_output = response.content
|
|
29
|
+
headers = response.headers
|
|
30
|
+
try:
|
|
31
|
+
response = response.json()
|
|
32
|
+
except Exception as response_error:
|
|
33
|
+
logging.error(f"JSON Conversion Error: {response_error}")
|
|
34
|
+
try:
|
|
35
|
+
response = Response(
|
|
36
|
+
information=response,
|
|
37
|
+
status_code=status_code,
|
|
38
|
+
raw_output=raw_output,
|
|
39
|
+
json_output=response,
|
|
40
|
+
headers=headers,
|
|
41
|
+
error=response_error,
|
|
42
|
+
)
|
|
43
|
+
except Exception as response_error:
|
|
44
|
+
logging.error(f"Response Model Application Error: {response_error}")
|
|
45
|
+
|
|
46
|
+
return response
|
clarity_api/version.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2012-2023 Audel Rouhi
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: clarity-api
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Microsoft Clarity Data Export API
|
|
5
|
+
Home-page: https://github.com/Knuckles-Team/clarity-api
|
|
6
|
+
Author: Audel Rouhi
|
|
7
|
+
Author-email: knucklessg1@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: License :: Public Domain
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: pydantic[email] (>=2.5.2)
|
|
22
|
+
Requires-Dist: requests (>=2.28.1)
|
|
23
|
+
Requires-Dist: urllib3 (>=1.26.13)
|
|
24
|
+
|
|
25
|
+
# Microsoft Clarity API
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+
|
|
40
|
+

|
|
41
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
*Version: 0.0.2*
|
|
48
|
+
|
|
49
|
+
**Microsoft Clarity Data Export API**
|
|
50
|
+
|
|
51
|
+
This Python library allows you to work with the dashboard data. The data can be structured over a specified date range
|
|
52
|
+
and can break down insights by up to three dimensions.
|
|
53
|
+
|
|
54
|
+
Find out more about the [Clarity Data Export API](https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-data-export-api)
|
|
55
|
+
|
|
56
|
+
This repository is actively maintained - Contributions are welcome!
|
|
57
|
+
|
|
58
|
+
<details>
|
|
59
|
+
<summary><b>Getting Started:</b></summary>
|
|
60
|
+
|
|
61
|
+
### Prerequisites
|
|
62
|
+
- An active Microsoft Clarity account. [Learn how to sign up for Clarity](https://clarity.microsoft.com).
|
|
63
|
+
- An API access token generated by the project's admin from the settings page.
|
|
64
|
+
- Python3.8+
|
|
65
|
+
|
|
66
|
+
### Obtaining Access Tokens
|
|
67
|
+
**Note**: Only project admins can manage access tokens.
|
|
68
|
+
|
|
69
|
+
1. Go to your Clarity project. Select `Settings` -> `Data Export` -> `Generate new API token`.
|
|
70
|
+
2. Provide a descriptive name for the token for easy identification.
|
|
71
|
+
|
|
72
|
+
## Parameters
|
|
73
|
+
- `numOfDays`: (1, 2, or 3) The number of days for the data export since the API call, relating to the last 24, 48, or 72 hours, respectively.
|
|
74
|
+
- `dimension1`: The first dimension to break down insights.
|
|
75
|
+
- `dimension2`: The second dimension to break down insights.
|
|
76
|
+
- `dimension3`: The third dimension to break down insights.
|
|
77
|
+
|
|
78
|
+
#### Dimension Options:
|
|
79
|
+
- Browser
|
|
80
|
+
- Device
|
|
81
|
+
- Country
|
|
82
|
+
- OS
|
|
83
|
+
- Source
|
|
84
|
+
- Medium
|
|
85
|
+
- Campaign
|
|
86
|
+
- Channel
|
|
87
|
+
- URL
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
<details>
|
|
92
|
+
<summary><b>Usage:</b></summary>
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
#!/usr/bin/python
|
|
96
|
+
# coding: utf-8
|
|
97
|
+
import clarity_api
|
|
98
|
+
|
|
99
|
+
# Use token generated from the steps above
|
|
100
|
+
token = "<TOKEN>"
|
|
101
|
+
url = "https://www.clarity.ms"
|
|
102
|
+
client = clarity_api.Api(url=url, token=token)
|
|
103
|
+
|
|
104
|
+
data = client.get_data_export(number_of_days=2, dimension_1="OS", dimension_2="Channel")
|
|
105
|
+
print("Pydantic Object:", data)
|
|
106
|
+
print("Raw Request Output:", data.raw_output)
|
|
107
|
+
print("JSON Request Output:", data.json_output)
|
|
108
|
+
print("Pydantic Object Model Dump:", data.model_dump())
|
|
109
|
+
print("Request Status Code:", data.status_code)
|
|
110
|
+
print("Request Error:", data.error)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
</details>
|
|
114
|
+
|
|
115
|
+
<details>
|
|
116
|
+
<summary><b>Installation Instructions:</b></summary>
|
|
117
|
+
|
|
118
|
+
Install Python Package
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -m pip install clarity-api
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
</details>
|
|
125
|
+
|
|
126
|
+
<details>
|
|
127
|
+
<summary><b>Tests:</b></summary>
|
|
128
|
+
|
|
129
|
+
pre-commit check
|
|
130
|
+
```bash
|
|
131
|
+
pre-commit run --all-files
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
pytest
|
|
135
|
+
```bash
|
|
136
|
+
pytest ./test/test_clarity_models.py
|
|
137
|
+
```
|
|
138
|
+
</details>
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
<details>
|
|
142
|
+
<summary><b>Repository Owners:</b></summary>
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+

|
|
149
|
+
</details>
|
|
150
|
+
|
|
151
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
clarity_api/__init__.py,sha256=1RbQDB040YNxdutHk3zNzd-3rpEAZXxdsq4HxJzUdmc,391
|
|
2
|
+
clarity_api/clarity_api.py,sha256=RNROb_rZ2d-iMQicWI2MGV3lJ_eq7OENFuHOtzuZNPE,3360
|
|
3
|
+
clarity_api/clarity_models.py,sha256=llLMupvobbtAaa0FFDD7NFUEity3BUHBmiQcf9Ac1nI,5269
|
|
4
|
+
clarity_api/decorators.py,sha256=teR4yHuA0h7QxKJFkwe4u_2n_-BR-oMXRZw1hhCCf_s,522
|
|
5
|
+
clarity_api/exceptions.py,sha256=y0R-KHDuSSh1gmeRSuzlFrq6UHl8FPffi2-Sgq1AeIM,469
|
|
6
|
+
clarity_api/utils.py,sha256=SnX5csZ7BP2mdx6ru904MtrOsIaJxTyalR5h-r7jWeE,1254
|
|
7
|
+
clarity_api/version.py,sha256=tcG0SGm7vrK-3XSjl3-NHRbQZhx3tWy90U_dzAHPjpg,116
|
|
8
|
+
clarity_api-0.0.2.dist-info/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
|
|
9
|
+
clarity_api-0.0.2.dist-info/METADATA,sha256=B9zvMcYwAMz3W0_nm_7WjsNpMPePxnb_yO-3VuSi-WI,5076
|
|
10
|
+
clarity_api-0.0.2.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
|
|
11
|
+
clarity_api-0.0.2.dist-info/top_level.txt,sha256=GzU1WAhzKvq2LNliEefbjBiag7nCE3A2W-vE2az0RiE,12
|
|
12
|
+
clarity_api-0.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
clarity_api
|