Example Projects

Six ready-to-use projects showing how to build cannabis applications with the Leefii API.

Strain Search Widget

JavaScript + HTML

Embed a cannabis strain search directly on your website. Users can search by name, type, or effect and see results with THC/CBD percentages and flavor profiles. Ideal for dispensary websites and cannabis blogs.

View Full Code Example
<!-- Strain Search Widget -->
<div id="leefii-strain-search">
  <input type="text" id="strain-query" placeholder="Search strains..."
    style="width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 8px;" />
  <div id="strain-results" style="margin-top: 12px;"></div>
</div>

<script>
const API_KEY = 'lf_live_your_key_here';
const input = document.getElementById('strain-query');
const results = document.getElementById('strain-results');

let timeout;
input.addEventListener('input', (e) => {
  clearTimeout(timeout);
  timeout = setTimeout(() => searchStrains(e.target.value), 300);
});

async function searchStrains(query) {
  if (!query || query.length < 2) {
    results.innerHTML = '';
    return;
  }

  const res = await fetch(
    `https://leefii.com/api/v1/search?q=${encodeURIComponent(query)}&type=strains&limit=5`,
    { headers: { 'X-API-Key': API_KEY } }
  );
  const { data } = await res.json();

  results.innerHTML = data.map(strain => `
    <div style="padding: 12px; border: 1px solid #eee; border-radius: 8px; margin-bottom: 8px;">
      <strong>${strain.name}</strong>
      <span style="background: #dcfce7; color: #166534; padding: 2px 8px;
        border-radius: 4px; font-size: 12px; margin-left: 8px;">${strain.type}</span>
      <div style="color: #666; font-size: 14px; margin-top: 4px;">
        THC: ${strain.thc}% | CBD: ${strain.cbd}%
      </div>
    </div>
  `).join('');
}
</script>

<p style="font-size: 12px; color: #666; margin-top: 16px;">
  Data by <a href="https://leefii.com" rel="dofollow" style="color: #16a34a;">Leefii</a>
</p>

Dispensary Finder Map

JavaScript

Build an interactive dispensary map using Google Maps and the Leefii dispensary API. Show dispensary locations as pins with info windows displaying name, rating, address, and delivery status.

View Full Code Example
// Dispensary Finder Map with Google Maps
const API_KEY = 'lf_live_your_key_here';
const GOOGLE_MAPS_KEY = 'your_google_maps_key';

async function initMap() {
  const map = new google.maps.Map(document.getElementById('map'), {
    center: { lat: 34.0522, lng: -118.2437 }, // Los Angeles
    zoom: 12,
  });

  // Fetch dispensaries from Leefii API
  const response = await fetch(
    'https://leefii.com/api/v1/dispensaries?state=CA&city=Los+Angeles&limit=50',
    { headers: { 'X-API-Key': API_KEY } }
  );
  const { data } = await response.json();

  // Add markers for each dispensary
  data.forEach(dispensary => {
    const marker = new google.maps.Marker({
      position: { lat: dispensary.lat, lng: dispensary.lng },
      map,
      title: dispensary.name,
    });

    const infoWindow = new google.maps.InfoWindow({
      content: `
        <div style="max-width: 250px;">
          <h3 style="margin: 0 0 4px;">${dispensary.name}</h3>
          <p style="color: #666; font-size: 13px; margin: 0 0 4px;">
            ${dispensary.address}
          </p>
          <p style="margin: 0;">
            Rating: ${dispensary.rating}/5
            ${dispensary.delivery ? ' | Delivery Available' : ''}
          </p>
        </div>
      `,
    });

    marker.addListener('click', () => infoWindow.open(map, marker));
  });
}

Deal Aggregator

Python

Display current cannabis deals from dispensaries on your blog or content site. This Python script fetches deals by state and generates HTML output you can embed or serve from your backend.

View Full Code Example
import requests
import os
from datetime import datetime

API_KEY = os.environ['LEEFII_API_KEY']

def fetch_deals(state, category=None, limit=20):
    """Fetch active cannabis deals for a given state."""
    params = {'state': state, 'limit': limit}
    if category:
        params['category'] = category

    response = requests.get(
        'https://leefii.com/api/v1/deals',
        params=params,
        headers={'X-API-Key': API_KEY}
    )
    return response.json()

def generate_html(deals_data):
    """Generate an HTML snippet for embedding deals."""
    if not deals_data['success']:
        return '<p>Unable to load deals.</p>'

    html = '<div class="leefii-deals">'
    for deal in deals_data['data']:
        html += f'''
        <div style="border: 1px solid #eee; padding: 16px;
                    border-radius: 8px; margin-bottom: 12px;">
          <div style="font-weight: bold; font-size: 18px; color: #16a34a;">
            {deal['discount']} Off
          </div>
          <div style="font-weight: 600; margin: 4px 0;">{deal['title']}</div>
          <div style="color: #666; font-size: 14px;">
            {deal['dispensary']} | {deal['category']}
          </div>
          <div style="color: #999; font-size: 12px; margin-top: 4px;">
            Expires: {deal['expires']}
          </div>
        </div>'''
    html += '</div>'
    html += '<p style="font-size: 12px;">Data by <a href="https://leefii.com">Leefii</a></p>'
    return html

# Fetch and display Colorado deals
deals = fetch_deals('CO', category='flower')
print(generate_html(deals))

# Fetch edible deals
edible_deals = fetch_deals('CA', category='edibles')
print(f"Found {edible_deals['meta']['total']} edible deals in California")

State Law Checker

React + TypeScript

Build a React component that lets users check cannabis laws for any US state. Displays recreational and medical legality, possession limits, home grow rules, and delivery regulations.

View Full Code Example
import { useState } from 'react';

interface StateLaw {
  state: string;
  stateCode: string;
  recreational: boolean;
  medical: boolean;
  possession_limit_oz: number;
  home_grow: boolean;
  home_grow_plants: number;
  delivery_legal: boolean;
  updated: string;
}

export function StateLawChecker() {
  const [stateCode, setStateCode] = useState('');
  const [law, setLaw] = useState<StateLaw | null>(null);
  const [loading, setLoading] = useState(false);

  async function checkLaw() {
    if (!stateCode) return;
    setLoading(true);
    try {
      const res = await fetch(
        `https://leefii.com/api/v1/laws/${stateCode.toUpperCase()}`,
        { headers: { 'X-API-Key': process.env.NEXT_PUBLIC_LEEFII_KEY! } }
      );
      const { data } = await res.json();
      setLaw(data);
    } catch (err) {
      console.error('Failed to fetch law data:', err);
    }
    setLoading(false);
  }

  return (
    <div style={{ maxWidth: 480, margin: '0 auto' }}>
      <h2>Cannabis Law Checker</h2>
      <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
        <input
          value={stateCode}
          onChange={(e) => setStateCode(e.target.value)}
          placeholder="Enter state code (e.g., CA)"
          maxLength={2}
          style={{ flex: 1, padding: '10px 14px', border: '1px solid #ddd',
                   borderRadius: 8 }}
        />
        <button onClick={checkLaw} disabled={loading}
          style={{ padding: '10px 20px', background: '#16a34a', color: '#fff',
                   border: 'none', borderRadius: 8, cursor: 'pointer' }}>
          {loading ? 'Checking...' : 'Check'}
        </button>
      </div>

      {law && (
        <div style={{ border: '1px solid #eee', borderRadius: 8, padding: 16 }}>
          <h3>{law.state} ({law.stateCode})</h3>
          <p>Recreational: {law.recreational ? 'Legal' : 'Not Legal'}</p>
          <p>Medical: {law.medical ? 'Legal' : 'Not Legal'}</p>
          <p>Possession Limit: {law.possession_limit_oz} oz</p>
          <p>Home Grow: {law.home_grow
            ? `Yes (up to ${law.home_grow_plants} plants)`
            : 'Not Allowed'}</p>
          <p>Delivery: {law.delivery_legal ? 'Legal' : 'Not Legal'}</p>
          <p style={{ fontSize: 12, color: '#999' }}>
            Last updated: {law.updated}
          </p>
        </div>
      )}
    </div>
  );
}

Cannabis Data Dashboard

JavaScript + Chart.js

Create a data visualization dashboard using Chart.js and the Leefii API. Display strain distribution by type, average THC content trends, and top dispensaries by rating.

View Full Code Example
import Chart from 'chart.js/auto';

const API_KEY = 'lf_live_your_key_here';
const BASE = 'https://leefii.com/api/v1';

async function buildDashboard() {
  // Fetch strain data for each type
  const types = ['indica', 'sativa', 'hybrid'];
  const counts = {};

  for (const type of types) {
    const res = await fetch(`${BASE}/strains?type=${type}&limit=1`, {
      headers: { 'X-API-Key': API_KEY }
    });
    const { meta } = await res.json();
    counts[type] = meta.total;
  }

  // Strain Type Distribution (Doughnut Chart)
  new Chart(document.getElementById('typeChart'), {
    type: 'doughnut',
    data: {
      labels: ['Indica', 'Sativa', 'Hybrid'],
      datasets: [{
        data: [counts.indica, counts.sativa, counts.hybrid],
        backgroundColor: ['#7c3aed', '#f59e0b', '#16a34a'],
      }]
    },
    options: {
      plugins: {
        title: { display: true, text: 'Strains by Type' }
      }
    }
  });

  // Top Dispensaries by Rating (Bar Chart)
  const dispRes = await fetch(`${BASE}/dispensaries?limit=10`, {
    headers: { 'X-API-Key': API_KEY }
  });
  const { data: dispensaries } = await dispRes.json();
  const sorted = dispensaries.sort((a, b) => b.rating - a.rating).slice(0, 8);

  new Chart(document.getElementById('ratingChart'), {
    type: 'bar',
    data: {
      labels: sorted.map(d => d.name.slice(0, 20)),
      datasets: [{
        label: 'Rating',
        data: sorted.map(d => d.rating),
        backgroundColor: '#16a34a',
      }]
    },
    options: {
      scales: { y: { min: 3, max: 5 } },
      plugins: {
        title: { display: true, text: 'Top Rated Dispensaries' }
      }
    }
  });
}

buildDashboard();

Mobile App Integration

React Native

Use the Leefii API in a React Native mobile app. This example shows a strain list screen with search, infinite scroll pagination, and navigation to a strain detail screen.

View Full Code Example
import React, { useState, useEffect, useCallback } from 'react';
import {
  View, Text, FlatList, TextInput, TouchableOpacity,
  ActivityIndicator, StyleSheet
} from 'react-native';

const API_KEY = 'lf_live_your_key_here';

export function StrainListScreen({ navigation }) {
  const [strains, setStrains] = useState([]);
  const [query, setQuery] = useState('');
  const [offset, setOffset] = useState(0);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(false);

  const fetchStrains = useCallback(async (reset = false) => {
    setLoading(true);
    const newOffset = reset ? 0 : offset;
    const url = query
      ? `https://leefii.com/api/v1/search?q=${query}&type=strains&limit=20&offset=${newOffset}`
      : `https://leefii.com/api/v1/strains?limit=20&offset=${newOffset}`;

    const res = await fetch(url, {
      headers: { 'X-API-Key': API_KEY }
    });
    const { data, meta } = await res.json();

    setStrains(prev => reset ? data : [...prev, ...data]);
    setTotal(meta.total);
    setOffset(newOffset + 20);
    setLoading(false);
  }, [query, offset]);

  useEffect(() => { fetchStrains(true); }, [query]);

  const renderStrain = ({ item }) => (
    <TouchableOpacity
      style={styles.card}
      onPress={() => navigation.navigate('StrainDetail', { slug: item.slug })}
    >
      <View style={styles.row}>
        <Text style={styles.name}>{item.name}</Text>
        <Text style={styles.badge}>{item.type}</Text>
      </View>
      <Text style={styles.thc}>THC: {item.thc}%</Text>
    </TouchableOpacity>
  );

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Search strains..."
        value={query}
        onChangeText={setQuery}
      />
      <FlatList
        data={strains}
        renderItem={renderStrain}
        keyExtractor={item => item.slug}
        onEndReached={() => offset < total && fetchStrains()}
        onEndReachedThreshold={0.5}
        ListFooterComponent={loading ? <ActivityIndicator /> : null}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#fff', padding: 16 },
  input: { borderWidth: 1, borderColor: '#ddd', borderRadius: 8,
           padding: 12, marginBottom: 12, fontSize: 16 },
  card: { padding: 14, borderBottomWidth: 1, borderColor: '#eee' },
  row: { flexDirection: 'row', alignItems: 'center', gap: 8 },
  name: { fontSize: 16, fontWeight: '600' },
  badge: { backgroundColor: '#dcfce7', color: '#166534', fontSize: 12,
           paddingHorizontal: 8, paddingVertical: 2, borderRadius: 4 },
  thc: { color: '#666', fontSize: 14, marginTop: 4 },
});

Open Source Examples

All example projects are available on GitHub. Star the repo, fork it, and build something amazing.

View on GitHub

Start Building Today

Get your free API key and bring these examples to life in your own projects.