# Python

## Overview

The Journify Python SDK allows you to send tracking data from any PHP application or website to the Journify backend. It simplifies the process of integrating your PHP-based systems with Journify’s analytics infrastructure, enabling seamless event and user tracking. You can use this SDK to collect and forward data to various destinations such as Facebook Ads (via CAPI), Google Ads, Salesforce, webhooks, and more.

This library is open-source, so you can [check it out on GitHub](https://github.com/journifyio/journify-python-sdk).

## Installation

You can install the SDK using pip:

```bash
pip install journify-python-sdk
```

## Initialization

Inside your app, you’ll want to set your **`write_key`** before making any analytics calls:

```python
import journify

journify.write_key = '<YOUR_WRITE_KEY>'
```

**Note:** If you need to send data to multiple Journify sources, you can initialize a new client for each `write_key`.

```python
import journify as first_source
import journify as second_source

first_source.write_key = '<YOUR_FIRST_WRITE_KEY>'
second_source.write_key = '<YOUR_SECOND_WRITE_KEY>'
```

The default initialization settings are production-ready and queue messages to be processed by a background thread.

In development, Journify recommends that you enable the following settings to help spot problems:

* `journify.debug` to log debugging information to the Python logger
* an `on_error` handler to print any error response you receive from Journify’s API.

```python
def on_journify_error(error, items):
    print("A Journify error occurred:", error)

journify.debug = True
journify.on_error = on_journify_error
```

If you don’t want to send information to Journify during testing, add the following code to your test:

```python
journify.send = False
```

Here are the available configuration options:

| Option                              | Description                                                                   |
| ----------------------------------- | ----------------------------------------------------------------------------- |
| `write_key` *string*                | Your write Key (default: `None`)                                              |
| `host` *string*                     | The tracking API that receives your events (default: `https://t.journify.io`) |
| `on_error` *function(error, items)* | Callback for errors (default: `None`)                                         |
| `debug` *boolean*                   | Set log level to debugging (default: `False`)                                 |
| `send` *boolean*                    | Whether to send messages to the tracking API or not (default: `True`)         |
| `sync_mode` *boolean*               | If `True` events are not batched (default: `False`)                           |
| `upload_size` *number*              | Batch size (default: `100`)                                                   |
| `upload_interval` *number*          | Upload interval in seconds (default: `0.5`)                                   |
| `max_queue_size` *number*           | Max size of the queue used to batch events (default: `10000`)                 |
| `gzip` *boolean*                    | Whether to compress http requests using Gzip or not (default: `False`)        |
| `timeout` *number*                  | Http timeout in seconds (default: `15`)                                       |
| `max_retries` *number*              | Max retries (default: `10`)                                                   |
| `thread` *number*                   | Number of threads (default: `1`)                                              |

## API

The Journify Python SDK has two main methods for sending data to Journify: `identify` and `track`. Each method serves a different purpose and can be used to send different types of data.

### Identify

The `identify` lets you record user traits. It includes a unique User ID and any optional traits you know about them.

Journify recommends that you call `identify` once when the user’s account is created, and later when their traits change.

Example `identify` call:

```python
journify.identify('019mr8mf4r', {
    'email': 'john@example.com',
    'name': 'John Smith',
    'friends': 30
})
```

The example `identify` call is identifying John by his unique User ID (the one you know him by in your database) and labeling him with `email`, `name` and `friends` traits.

The `identify` call has the following fields:

<table><thead><tr><th width="327">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>user_id</code> <em>string or int</em></td><td>The ID for this user in your database.</td></tr><tr><td><code>traits</code> <em>dict, optional</em></td><td>A dictionary of traits you know about the user. Things like: <code>email</code>, <code>name</code> or <code>friends</code>.</td></tr><tr><td><code>timestamp</code> <em>datetime, optional</em></td><td>A <code>datetime</code> object representing when the <code>identify</code> took place. This is most useful if you import historical data. If the <code>identify</code> call just happened, leave it blank and Journify will use the server’s time.</td></tr><tr><td><code>anonymous_id</code> <em>string or int, optional</em></td><td>An anonymous session ID for this user.</td></tr></tbody></table>

### Track

`track` lets you record the actions your users perform. Every action can also have associated properties.

Example of events you might want to track include **add\_to\_cart**, **purchase**, or **begin\_checkout**.

To get started, Journify recommends tracking all important events.

Example `track` call:

```python
journify.track('f4ca124298', 'Signed Up', {
  'plan': 'Enterprise'
})
```

This call informs Journify that your user just triggered the **Signed Up** event and chose your hypothetical `'Enterprise'` plan.

`track` event properties can be anything you want to record, for example:

```python
journify.track('f4ca124298', 'Article Bookmarked', {
    'title': 'Snow Fall',
    'subtitle': 'The Avalance at Tunnel Creek',
    'author': 'John Branch'
})
```

The `track` method has the following fields:

| Field                                    | Description                                                                                                                                                                                   |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user_id` *string*                       | The ID for this user in your database.                                                                                                                                                        |
| `event` *string*                         | The name of the event you’re tracking. Use human-readable names like **Song Played** or **Status Updated**.                                                                                   |
| `properties` *dict, optional*            | A dictionary of properties for the event. If the event was **Product Added**, it might have properties like `price` or `product`.                                                             |
| `timestamp` *datetime, optional*         | A `datetime` object representing when the `track` took place. This is most useful if you’re importing historical data. If the `track` just happened, leave it blank to use the server’s time. |
| `anonymous_id` *string or int, optional* | An anonymous session ID for this user.                                                                                                                                                        |

### Page

The `page` method lets you record page views on your website, along with optional extra information about the page being viewed.

Example `page` call:

```python
journify.page('user_id', 'Docs', 'Python', {
  'url': 'https://journify.io'
})
```

The `page` call has the following fields:

| Field                                    | Description                                                                                                                                                                                 |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user_id` \_string                       | The ID for this user in your database.                                                                                                                                                      |
| `category` *string, optional*            | The category of the page. Useful for things like ecommerce where many pages often live under a larger category.                                                                             |
| `name` *string, optional*                | The name of the page, for example **Signup** or **Home**.                                                                                                                                   |
| `properties` *dict, optional*            | The page properties. To see a reference of reserved page properties, see the spec [here](https://docs.journify.io/tracking/page-event#properties).                                          |
| `timestamp` *datetime, optional*         | A `datetime` object representing when the `page` took place. This is most useful if you’re importing historical data. If the `page` just happened, leave it blank to use the server’s time. |
| `anonymous_id` *string or int, optional* | An anonymous session ID for this user.                                                                                                                                                      |

## Tips

### Historical import

You can import historical data by adding the `timestamp` argument to any of your method calls. This can be helpful if you’ve just switched to Journify.

Historical imports can only be done into destinations that can accept historical timestamped data. Most analytics tools can handle that type of data just fine. One common destination that does not accept historical data is Google Analytics since their API cannot accept historical data.

If you track things that are happening right now, omit the `timestamp` and Journify’s servers will timestamp the requests for you.

```python
import datetime
from dateutil.tz import tzutc

timestamp = datetime.datetime(2538, 10, 17, 0, 0, 0, 0, tzinfo=tzutc())
journify.track('019mr8mf4r', 'Bought a game', {'game': 'Duke Nukem forever'}, 
    timestamp=timestamp)
```

### Batching

Journify’s libraries are built to support high-performance environments. It’s safe to use the PHP SDK on a web server that serves hundreds of requests per second.

Every method you call **does not** result in an HTTP request, but is queued in memory instead. Messages are flushed in batch in the background, which allows for much faster operation.

### What happens if there are just too many messages?

If the module detects that it can’t flush faster than it’s receiving messages, it’ll simply stop accepting messages. This means your program will never crash because of a backed-up queue. The default `max_queue_size` is `10000`.

### How do I flush right now?!

You can also flush on demand. For example, at the end of your program, you’ll want to flush to make sure there’s nothing left in the queue. Just call the `flush` method:

```python
journify.flush()
```

Calling this method will *block* the calling thread until there are no messages left in the queue. You’ll want to use it as part of your cleanup scripts and avoid using it as part of the request lifecycle.

### Background threads and synchronous mode <a href="#background-threads-and-synchronous-mode" id="background-threads-and-synchronous-mode"></a>

In some cases, you will want to disable threads and send each request synchronously. To do so, you can use the `sync_mode` option:

```python
import journify

journify.write_key = '<YOUR_WRITE_KEY>'
journify.sync_mode = True
```

## Source schema

When creating a source, it's required to attach a source schema that outlines which events and properties you are expecting to receive from this source. You can select a schema from our catalog or create a new one from scratch following [the JSON Schema Draft-07 spec](https://json-schema.org/draft-07).

## Troubleshooting

### Common errors

So far, our customers haven’t encountered any issues with this source. If anything unexpected comes up, feel free to [contact us](mailto:support@journify.io) — we’re ready to assist.

### Live debugger

Journify provides complete visibility into what events you are receiving from the source once it's connected with Journify.
