Skip to content

Deploying Bitpoll

Bitpoll is an innovative, privacy-focused cryptocurrency-based polling and voting application that leverages blockchain technology to create secure, transparent, and tamper-proof voting systems. Built with modern web technologies and cryptographic principles, Bitpoll enables organizations, communities, and researchers to conduct polls and surveys where each vote is cryptographically verified and cannot be manipulated. Whether you’re running surveys, making community decisions, or collecting data with verifiable integrity, Bitpoll provides a decentralized alternative to traditional polling platforms.

Why Bitpoll?

Bitpoll stands out in the polling and voting landscape with its focus on security, transparency, and decentralization:

  • Blockchain Verification: Each vote is cryptographically signed and verified on the blockchain
  • Tamper-Proof Results: Votes cannot be altered or deleted once cast
  • Privacy-Preserving: Voter identities protected while maintaining vote authenticity
  • Decentralized: No single point of failure or control
  • Transparent Voting: Complete audit trail of all votes and voting activity
  • No Third-Party: Run your own polling infrastructure without intermediaries
  • Real-Time Results: Instant vote tallying and result updates
  • Customizable Polls: Create polls with multiple question types and options
  • Multiple Answer Formats: Support for yes/no, multiple choice, and ranking polls
  • Voter Authentication: Flexible authentication methods (email, social, cryptocurrency addresses)
  • Result Analytics: Detailed breakdowns and visualizations of poll results
  • Export Capabilities: Download results in multiple formats (CSV, JSON, PDF)
  • API Access: Programmatic access for integration with other systems
  • Open Source: MIT licensed with full source code transparency
  • Scalable Architecture: Handle high-volume voting with ease
  • Security Auditable: Full access to voting mechanics for verification

Bitpoll is ideal for organizations, communities, researchers, governance systems, cooperatives, DAOs, and anyone who needs verifiable, transparent voting mechanisms. With persistent storage on Klutch.sh, all voting data is secure and permanently auditable.

Prerequisites

Before deploying Bitpoll, ensure you have:

  • A Klutch.sh account
  • A GitHub repository with your Bitpoll deployment configuration
  • Basic familiarity with Docker, Git, and blockchain concepts
  • A domain name (recommended for production voting)
  • Understanding of polling and voting mechanics
  • Optional: cryptocurrency wallet integration for voter authentication

Important Considerations

Deploying Bitpoll

  1. Create a New Project

    Log in to your Klutch.sh dashboard and create a new project for your Bitpoll deployment.

  2. Prepare Your Repository

    Create a GitHub repository with the following structure for your Bitpoll deployment:

    bitpoll-deploy/
    ├─ Dockerfile
    ├─ .env.example
    ├─ docker-entrypoint.sh
    ├─ .gitignore
    └─ README.md

    Here’s a Dockerfile for Bitpoll:

    FROM python:3.11-slim
    # Install required system dependencies
    RUN apt-get update && apt-get install -y \
    curl \
    git \
    build-essential \
    libssl-dev \
    libffi-dev \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*
    # Set working directory
    WORKDIR /app
    # Clone Bitpoll repository
    RUN git clone https://github.com/bitpoll/bitpoll.git . && \
    git checkout main
    # Install Python dependencies
    RUN pip install --no-cache-dir -r requirements.txt
    # Create necessary directories
    RUN mkdir -p /app/data \
    /app/logs \
    /app/media \
    /app/static && \
    chmod -R 755 /app
    # Copy entrypoint script
    COPY docker-entrypoint.sh /
    RUN chmod +x /docker-entrypoint.sh
    # Expose port
    EXPOSE 8000
    # Health check
    HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:8000/api/health || exit 1
    # Run entrypoint
    ENTRYPOINT ["/docker-entrypoint.sh"]
    CMD ["start"]

    Create a docker-entrypoint.sh file:

    #!/bin/bash
    set -e
    # Wait for database if configured
    if [ -n "$DATABASE_URL" ]; then
    echo "Waiting for database connection..."
    MAX_ATTEMPTS=30
    ATTEMPTS=0
    while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
    if python -c "import psycopg2; psycopg2.connect('$DATABASE_URL')" 2>/dev/null; then
    echo "Database is ready!"
    break
    fi
    ATTEMPTS=$((ATTEMPTS + 1))
    sleep 1
    done
    fi
    # Run migrations
    if [ ! -f /app/data/migrated ]; then
    echo "Running database migrations..."
    python manage.py migrate --noinput
    python manage.py collectstatic --noinput
    touch /app/data/migrated
    fi
    # Set permissions
    chmod -R 755 /app
    if [ "$1" = "start" ]; then
    # Start the application
    python -m gunicorn bitpoll.wsgi:application --bind 0.0.0.0:8000 --workers 4 --timeout 120
    else
    exec "$@"
    fi

    Create a .env.example file:

    Terminal window
    # Application Configuration
    APP_URL=https://yourdomain.com
    APP_PORT=8000
    ENVIRONMENT=production
    DEBUG=false
    SECRET_KEY=your-secret-key-here
    # Database Configuration
    DATABASE_URL=postgresql://bitpoll_user:password@db:5432/bitpoll
    DB_ENGINE=django.db.backends.postgresql
    # Admin Configuration
    ADMIN_USERNAME=admin
    ADMIN_PASSWORD=secure_password_here
    ADMIN_EMAIL=admin@yourdomain.com
    # Blockchain Configuration
    BLOCKCHAIN_ENABLED=true
    BLOCKCHAIN_NETWORK=ethereum
    BLOCKCHAIN_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-api-key
    BLOCKCHAIN_CONTRACT_ADDRESS=0x
    # Email Configuration
    EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
    EMAIL_HOST=smtp.gmail.com
    EMAIL_PORT=587
    EMAIL_HOST_USER=your-email@gmail.com
    EMAIL_HOST_PASSWORD=your-app-password
    EMAIL_USE_TLS=true
    DEFAULT_FROM_EMAIL=noreply@yourdomain.com
    # Poll Configuration
    POLLS_ENABLED=true
    ALLOW_ANONYMOUS_VOTING=false
    MAX_POLL_DURATION_DAYS=365
    DEFAULT_POLL_EXPIRATION_DAYS=30
    # Security
    REQUIRE_HTTPS=true
    ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
    CSRF_COOKIE_SECURE=true
    SESSION_COOKIE_SECURE=true
    # Features
    ENABLE_BLOCKCHAIN_VERIFICATION=true
    ENABLE_VOTE_EXPORT=true
    ENABLE_API=true
    ENABLE_ANALYTICS=true

    Commit and push to your GitHub repository:

    Terminal window
    git init
    git add .
    git commit -m "Initial Bitpoll deployment"
    git remote add origin https://github.com/yourusername/bitpoll-deploy.git
    git push -u origin main
  3. Create a New App

    In the Klutch.sh dashboard:

    • Click “Create New App”
    • Select your GitHub repository containing the Dockerfile
    • Choose the branch (typically main or master)
    • Klutch.sh will automatically detect the Dockerfile in the root directory
  4. Configure Environment Variables

    Set up these essential environment variables in your Klutch.sh dashboard:

    VariableDescriptionExample
    APP_URLYour application domainhttps://polls.example.com
    APP_PORTApplication port8000
    ENVIRONMENTEnvironment (production or development)production
    DEBUGDebug mode (false for production)false
    SECRET_KEYDjango secret key (generate secure random string)secure-random-string
    DATABASE_URLDatabase connection stringpostgresql://user:pass@host/db
    ADMIN_USERNAMEAdmin account usernameadmin
    ADMIN_PASSWORDAdmin account password (use strong password)secure_password
    ADMIN_EMAILAdmin email addressadmin@yourdomain.com
    BLOCKCHAIN_ENABLEDEnable blockchain verificationtrue
    BLOCKCHAIN_NETWORKBlockchain networkethereum
    BLOCKCHAIN_RPC_URLBlockchain RPC endpointhttps://eth-mainnet...
    EMAIL_HOSTSMTP server hostnamesmtp.gmail.com
    EMAIL_PORTSMTP port587
    EMAIL_HOST_USERSMTP usernameyour-email@gmail.com
    EMAIL_HOST_PASSWORDSMTP passwordapp_password
    ALLOW_ANONYMOUS_VOTINGAllow anonymous votesfalse
    ENABLE_BLOCKCHAIN_VERIFICATIONVerify votes on blockchaintrue
  5. Configure Persistent Storage

    Bitpoll requires persistent storage for poll data, voting records, and media. Add persistent volumes:

    Mount PathDescriptionRecommended Size
    /app/dataPoll data and voting records100GB+
    /app/logsApplication logs20GB
    /app/mediaPoll media files and attachments50GB
    /app/staticStatic files and assets5GB

    In the Klutch.sh dashboard:

    • Navigate to your app settings
    • Go to the “Volumes” section
    • Click “Add Volume” for each mount path
    • Set mount paths and sizes as specified above
  6. Set Network Configuration

    Configure your app’s network settings:

    • Select traffic type: HTTP (Bitpoll uses standard web ports)
    • Recommended internal port: 8000 (as specified in Dockerfile)
    • Klutch.sh will automatically handle HTTPS termination via reverse proxy
    • Ensure ports 80 and 443 are accessible from your domain
  7. Configure Custom Domain

    Bitpoll works best with a custom domain for professional polling:

    • Navigate to your app’s “Domains” section in Klutch.sh
    • Click “Add Custom Domain”
    • Enter your domain (e.g., polls.yourdomain.com)
    • Configure DNS with a CNAME record to point to your Klutch.sh app
    • Update APP_URL environment variable to match your domain
    • Klutch.sh will automatically provision SSL certificates
  8. Deploy Your App

    • Review all settings and environment variables
    • Click “Deploy”
    • Klutch.sh will build the Docker image and start your Bitpoll instance
    • Wait for the deployment to complete (typically 5-10 minutes)
    • Access your Bitpoll instance at your configured domain
    • Log in with admin credentials to begin creating polls

Initial Setup and Configuration

After deployment completes, access your Bitpoll instance to complete setup.

Accessing Bitpoll Admin Panel

Navigate to your domain: https://yourdomain.com/admin/

Log in with the admin credentials you configured in environment variables.

Creating Your First Poll

  1. Click “Create New Poll” in the admin dashboard
  2. Configure poll details:
    • Poll title and description
    • Poll category or topic
    • Start and end dates/times
  3. Add poll questions:
    • Choose question type (yes/no, multiple choice, ranking)
    • Add answer options
    • Set option weights (if applicable)
  4. Configure voting settings:
    • Allow anonymous voting (if desired)
    • Require authentication method
    • Set maximum votes per voter
  5. Configure blockchain verification:
    • Enable/disable blockchain verification
    • Set confirmation requirements
  6. Publish poll and share link

Setting Up Voter Authentication

Configure how voters authenticate:

  1. Navigate to “Authentication Settings”
  2. Choose authentication methods:
    • Email-based authentication
    • Social login integration
    • Cryptocurrency wallet verification
  3. Configure requirements:
    • Email verification required
    • Voter registration required
    • Anonymous voting allowed
  4. Save authentication settings

Configuring Poll Questions

Create engaging and clear poll questions:

  1. Add poll question
  2. Select question type:
    • Yes/No: Binary choice
    • Multiple Choice: Single selection from options
    • Multiple Select: Multiple selections allowed
    • Ranking: Order options by preference
    • Rating Scale: Numeric rating system
  3. Add question options
  4. Set question as required or optional
  5. Configure skip option if needed

Environment Variable Examples

Basic Configuration

Terminal window
APP_URL=https://polls.yourdomain.com
APP_PORT=8000
ENVIRONMENT=production
DEBUG=false
SECRET_KEY=your-django-secret-key
DATABASE_URL=postgresql://user:password@db:5432/bitpoll
ADMIN_USERNAME=admin
ADMIN_PASSWORD=secure_password
BLOCKCHAIN_ENABLED=true
BLOCKCHAIN_NETWORK=ethereum

Complete Production Configuration

Terminal window
# Application Settings
APP_URL=https://polls.yourdomain.com
APP_PORT=8000
ENVIRONMENT=production
DEBUG=false
SECRET_KEY=your-secure-django-secret-key
LOG_LEVEL=info
# Database Configuration
DATABASE_URL=postgresql://bitpoll_user:secure_password@db:5432/bitpoll
DB_ENGINE=django.db.backends.postgresql
DB_POOL_SIZE=20
# Admin Configuration
ADMIN_USERNAME=admin
ADMIN_PASSWORD=secure_admin_password
ADMIN_EMAIL=admin@yourdomain.com
# Blockchain Configuration
BLOCKCHAIN_ENABLED=true
BLOCKCHAIN_NETWORK=ethereum
BLOCKCHAIN_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-api-key
BLOCKCHAIN_CONTRACT_ADDRESS=0x...
BLOCKCHAIN_CONFIRMATIONS_REQUIRED=3
BLOCKCHAIN_GAS_MULTIPLIER=1.2
# Email Configuration
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
EMAIL_USE_TLS=true
DEFAULT_FROM_EMAIL=noreply@yourdomain.com
EMAIL_TIMEOUT=10
# Poll Configuration
POLLS_ENABLED=true
ALLOW_ANONYMOUS_VOTING=false
REQUIRE_EMAIL_VERIFICATION=true
MAX_POLL_DURATION_DAYS=365
DEFAULT_POLL_EXPIRATION_DAYS=30
MAX_POLLS_PER_USER=100
MAX_OPTIONS_PER_QUESTION=20
# Voting Configuration
VOTING_ENABLED=true
ALLOW_VOTE_CHANGES=true
VOTE_CHANGE_DEADLINE_DAYS=7
REQUIRE_ONE_VOTE_PER_QUESTION=true
# Security
REQUIRE_HTTPS=true
ALLOWED_HOSTS=polls.yourdomain.com
CSRF_COOKIE_SECURE=true
SESSION_COOKIE_SECURE=true
CORS_ALLOWED_ORIGINS=https://yourdomain.com
# Features
ENABLE_BLOCKCHAIN_VERIFICATION=true
ENABLE_VOTE_EXPORT=true
ENABLE_API=true
ENABLE_ANALYTICS=true
ENABLE_REAL_TIME_RESULTS=true
ENABLE_RESULT_PREVIEW=false
# Analytics
ANALYTICS_ENABLED=true
TRACK_IP_ADDRESSES=false
PRIVACY_MODE=strict

Sample Code and Getting Started

Python - Creating Polls via API

import requests
import json
from datetime import datetime, timedelta
class BitpollClient:
def __init__(self, base_url, admin_token=None):
self.base_url = base_url
self.api_url = f'{base_url}/api'
self.admin_token = admin_token
self.headers = {'Content-Type': 'application/json'}
if admin_token:
self.headers['Authorization'] = f'Bearer {admin_token}'
def create_poll(self, title, description, questions,
start_date=None, end_date=None, allow_anonymous=False):
"""Create a new poll"""
try:
payload = {
'title': title,
'description': description,
'questions': questions,
'start_date': start_date or datetime.now().isoformat(),
'end_date': end_date or (datetime.now() + timedelta(days=30)).isoformat(),
'allow_anonymous_voting': allow_anonymous,
'blockchain_verification_enabled': True
}
response = requests.post(
f'{self.api_url}/polls',
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating poll: {e}")
return None
def get_poll(self, poll_id):
"""Retrieve poll details"""
try:
response = requests.get(
f'{self.api_url}/polls/{poll_id}',
headers=self.headers
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error retrieving poll: {e}")
return None
def get_poll_results(self, poll_id, include_blockchain_status=True):
"""Get poll results and analytics"""
try:
response = requests.get(
f'{self.api_url}/polls/{poll_id}/results',
headers=self.headers,
params={'include_blockchain': include_blockchain_status}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error retrieving results: {e}")
return None
def cast_vote(self, poll_id, voter_token, answers):
"""Cast a vote on a poll"""
try:
headers = {**self.headers, 'Authorization': f'Bearer {voter_token}'}
payload = {
'poll_id': poll_id,
'answers': answers
}
response = requests.post(
f'{self.api_url}/votes',
headers=headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error casting vote: {e}")
return None
def change_vote(self, vote_id, voter_token, new_answers):
"""Change an existing vote"""
try:
headers = {**self.headers, 'Authorization': f'Bearer {voter_token}'}
payload = {'answers': new_answers}
response = requests.put(
f'{self.api_url}/votes/{vote_id}',
headers=headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error changing vote: {e}")
return None
def export_results(self, poll_id, format='csv'):
"""Export poll results"""
try:
response = requests.get(
f'{self.api_url}/polls/{poll_id}/export',
headers=self.headers,
params={'format': format}
)
response.raise_for_status()
return response.content
except requests.exceptions.RequestException as e:
print(f"Error exporting results: {e}")
return None
def list_polls(self, status='active', limit=50, offset=0):
"""List polls with optional filtering"""
try:
response = requests.get(
f'{self.api_url}/polls',
headers=self.headers,
params={
'status': status,
'limit': limit,
'offset': offset
}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error listing polls: {e}")
return None
# Usage example
if __name__ == "__main__":
client = BitpollClient('https://polls.yourdomain.com', admin_token='your-admin-token')
# Create a poll
questions = [
{
'text': 'Which feature should we prioritize?',
'type': 'multiple_choice',
'options': [
{'text': 'Better analytics'},
{'text': 'Mobile app'},
{'text': 'Integration API'},
{'text': 'Advanced permissions'}
]
},
{
'text': 'How satisfied are you with our service?',
'type': 'rating_scale',
'scale': 5
}
]
poll = client.create_poll(
title='Product Development Roadmap Survey',
description='Help us decide what to build next',
questions=questions,
allow_anonymous=False
)
if poll:
poll_id = poll['id']
print(f"Poll created: {poll_id}")
# Get poll details
poll_data = client.get_poll(poll_id)
print(f"Poll details: {poll_data}")
# Get results
results = client.get_poll_results(poll_id)
print(f"Poll results: {results}")
# Export results
csv_data = client.export_results(poll_id, format='csv')
with open('poll_results.csv', 'wb') as f:
f.write(csv_data)
# List all polls
all_polls = client.list_polls(status='active')
print(f"Active polls: {all_polls}")

JavaScript - Poll Widget and Voting Interface

const POLL_API_URL = 'https://polls.yourdomain.com/api';
class BitpollWidget {
constructor(pollId, containerId) {
this.pollId = pollId;
this.containerId = containerId;
this.poll = null;
}
async loadPoll() {
try {
const response = await fetch(`${POLL_API_URL}/polls/${this.pollId}`);
if (!response.ok) throw new Error('Failed to load poll');
this.poll = await response.json();
this.render();
} catch (error) {
console.error('Error loading poll:', error);
this.renderError('Failed to load poll');
}
}
render() {
const container = document.getElementById(this.containerId);
if (!container) return;
let html = `
<div class="bitpoll-widget">
<div class="poll-header">
<h2>${this.poll.title}</h2>
<p>${this.poll.description}</p>
</div>
<form id="poll-form-${this.pollId}">
`;
this.poll.questions.forEach((question, index) => {
html += this.renderQuestion(question, index);
});
html += `
<div class="poll-actions">
<button type="submit" class="btn-submit">Submit Vote</button>
<button type="button" class="btn-results" onclick="this.pollWidget.loadResults()">View Results</button>
</div>
</form>
<div id="results-${this.pollId}"></div>
</div>
`;
container.innerHTML = html;
this.pollWidget = this;
document.getElementById(`poll-form-${this.pollId}`).addEventListener('submit',
(e) => this.handleSubmit(e));
}
renderQuestion(question, index) {
let html = `<div class="poll-question">`;
html += `<label>${question.text}</label>`;
if (question.type === 'multiple_choice' || question.type === 'multiple_select') {
const inputType = question.type === 'multiple_choice' ? 'radio' : 'checkbox';
question.options.forEach((option, optIndex) => {
const optId = `${this.pollId}-q${index}-opt${optIndex}`;
html += `
<div class="poll-option">
<input type="${inputType}" id="${optId}" name="question_${index}" value="${optIndex}">
<label for="${optId}">${option.text}</label>
</div>
`;
});
} else if (question.type === 'rating_scale') {
for (let i = 1; i <= question.scale; i++) {
html += `
<label class="rating-option">
<input type="radio" name="question_${index}" value="${i}">
${i}
</label>
`;
}
} else if (question.type === 'text') {
html += `<input type="text" name="question_${index}" class="poll-input">`;
}
html += `</div>`;
return html;
}
async handleSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
const answers = [];
for (let [key, value] of formData.entries()) {
answers.push({
question_index: parseInt(key.split('_')[1]),
answer: value
});
}
try {
const response = await fetch(`${POLL_API_URL}/votes`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.getVoterToken()}`
},
body: JSON.stringify({
poll_id: this.pollId,
answers: answers
})
});
if (!response.ok) throw new Error('Failed to submit vote');
const result = await response.json();
this.renderSuccess('Vote submitted successfully!');
// Reload results
setTimeout(() => this.loadResults(), 1000);
} catch (error) {
console.error('Error submitting vote:', error);
this.renderError('Failed to submit vote');
}
}
async loadResults() {
try {
const response = await fetch(
`${POLL_API_URL}/polls/${this.pollId}/results`
);
if (!response.ok) throw new Error('Failed to load results');
const results = await response.json();
this.renderResults(results);
} catch (error) {
console.error('Error loading results:', error);
this.renderError('Failed to load results');
}
}
renderResults(results) {
const container = document.getElementById(`results-${this.pollId}`);
if (!container) return;
let html = '<div class="poll-results"><h3>Poll Results</h3>';
results.questions.forEach((question, index) => {
html += `<div class="result-question"><h4>${question.text}</h4>`;
question.results.forEach((result) => {
const percentage = result.percentage || 0;
html += `
<div class="result-bar">
<div class="result-label">${result.text || result.value}</div>
<div class="result-progress">
<div class="result-fill" style="width: ${percentage}%"></div>
</div>
<div class="result-stats">${result.votes} votes (${percentage.toFixed(1)}%)</div>
</div>
`;
});
html += '</div>';
});
html += `<div class="result-footer">
Total Votes: ${results.total_votes}
<br>
Blockchain Verified: ${results.blockchain_verified ? 'Yes' : 'No'}
</div></div>`;
container.innerHTML = html;
}
renderSuccess(message) {
const container = document.getElementById(this.containerId);
const successDiv = document.createElement('div');
successDiv.className = 'poll-success';
successDiv.textContent = message;
container.prepend(successDiv);
setTimeout(() => successDiv.remove(), 5000);
}
renderError(message) {
const container = document.getElementById(this.containerId);
const errorDiv = document.createElement('div');
errorDiv.className = 'poll-error';
errorDiv.textContent = message;
container.prepend(errorDiv);
setTimeout(() => errorDiv.remove(), 5000);
}
getVoterToken() {
// Get from localStorage or session
return localStorage.getItem('bitpoll_voter_token') || '';
}
}
// Usage
document.addEventListener('DOMContentLoaded', () => {
const widget = new BitpollWidget('poll-123', 'poll-container');
widget.loadPoll();
});

cURL - API Integration Examples

Terminal window
# Create a poll
curl -X POST https://polls.yourdomain.com/api/polls \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"title": "Product Feedback Survey",
"description": "Help us improve our product",
"questions": [
{
"text": "How would you rate our product?",
"type": "rating_scale",
"scale": 5
}
]
}'
# Get poll details
curl -X GET https://polls.yourdomain.com/api/polls/{poll_id}
# Get poll results
curl -X GET https://polls.yourdomain.com/api/polls/{poll_id}/results
# Cast a vote
curl -X POST https://polls.yourdomain.com/api/votes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_VOTER_TOKEN" \
-d '{
"poll_id": "poll-id",
"answers": [
{"question_index": 0, "answer": "4"}
]
}'
# Export poll results as CSV
curl -X GET "https://polls.yourdomain.com/api/polls/{poll_id}/export?format=csv" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-o poll_results.csv
# List active polls
curl -X GET "https://polls.yourdomain.com/api/polls?status=active&limit=20"

Docker Compose for Local Development

For local testing before deploying to Klutch.sh:

version: '3.8'
services:
bitpoll:
build: .
container_name: bitpoll-app
environment:
APP_URL: http://localhost:8000
APP_PORT: 8000
ENVIRONMENT: development
DEBUG: "true"
SECRET_KEY: dev-secret-key-change-in-production
DATABASE_URL: postgresql://bitpoll:bitpoll@db:5432/bitpoll
ADMIN_USERNAME: admin
ADMIN_PASSWORD: admin123
BLOCKCHAIN_ENABLED: "false"
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
ports:
- "8000:8000"
volumes:
- ./:/app
- ./data:/app/data
- ./logs:/app/logs
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
container_name: bitpoll-db
environment:
POSTGRES_USER: bitpoll
POSTGRES_PASSWORD: bitpoll
POSTGRES_DB: bitpoll
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:

To run locally:

Terminal window
docker-compose up -d

Access Bitpoll at http://localhost:8000

Poll Configuration and Best Practices

Creating Effective Polls

Design polls for maximum engagement:

  1. Clear Titles: Use descriptive, concise poll titles
  2. Good Descriptions: Explain poll purpose and context
  3. Balanced Options: Provide balanced, mutually exclusive options
  4. Appropriate Length: Keep polls to 5-10 questions maximum
  5. Clear Questions: Use simple, unambiguous language
  6. Logical Flow: Order questions from general to specific

Voter Authentication Options

Configure voter verification methods:

  1. Email Authentication: Verify voter email address
  2. Social Login: Use OAuth providers (Google, GitHub, etc.)
  3. Cryptocurrency Wallet: Verify blockchain wallet address
  4. Registration System: Require voter registration
  5. Single Vote Per Email: Prevent duplicate voting

Result Analysis and Reporting

Analyze poll results effectively:

  1. View real-time results as votes come in
  2. Export results in CSV, JSON, or PDF format
  3. Analyze demographic breakdowns if available
  4. Compare results across questions
  5. Identify trends and patterns
  6. Share results with stakeholders

Security and Blockchain Verification

Vote Integrity

Ensure vote authenticity:

  • Each vote cryptographically signed
  • Blockchain verification prevents tampering
  • Immutable voting audit trail
  • Transaction hash for verification
  • Voter signature validation

Voter Privacy

Protect voter identities while maintaining transparency:

  • Anonymous voting options
  • No IP address logging
  • Voter anonymity settings
  • Privacy-preserving authentication
  • GDPR and privacy compliance

Blockchain Integration

Configure blockchain verification:

# Blockchain configuration for vote verification
BLOCKCHAIN_CONFIG = {
'network': 'ethereum',
'rpc_url': 'https://eth-mainnet.g.alchemy.com/v2/your-key',
'contract_address': '0x...',
'confirmations_required': 3,
'gas_multiplier': 1.2
}
# Vote verification function
def verify_vote_on_blockchain(vote_hash, transaction_hash):
"""Verify vote exists on blockchain"""
# Connect to blockchain
# Retrieve transaction
# Verify vote hash matches
# Check confirmations
# Return verification status
pass

Backup and Recovery

Automated Backups

Regular backup of polling data:

#!/bin/bash
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Backup database
pg_dump postgresql://user:pass@db:5432/bitpoll > \
$BACKUP_DIR/bitpoll_db_$TIMESTAMP.sql
# Backup media and uploads
tar -czf $BACKUP_DIR/bitpoll_media_$TIMESTAMP.tar.gz /app/media
# Keep only last 30 days
find $BACKUP_DIR -name "bitpoll_*" -mtime +30 -delete
echo "Backup completed: $TIMESTAMP"

Performance Optimization

Database Optimization

-- Create indexes for common queries
CREATE INDEX idx_poll_status ON polls(status);
CREATE INDEX idx_poll_created ON polls(created_at);
CREATE INDEX idx_vote_poll ON votes(poll_id);
CREATE INDEX idx_vote_created ON votes(created_at);

Caching Strategy

Enable caching for performance:

Terminal window
CACHE_ENABLED=true
CACHE_BACKEND=redis
REDIS_URL=redis://localhost:6379
CACHE_TTL=3600

Monitoring and Analytics

Poll Analytics

Track voting engagement:

  • Total votes per poll
  • Votes per day/hour
  • Voter participation rate
  • Question completion rate
  • Result distribution analysis
  • Voter demographics (if enabled)

Performance Monitoring

Monitor system performance:

  • Response time metrics
  • Database query performance
  • API endpoint usage
  • Cache hit rates
  • Error rates and logs

Troubleshooting

Common Issues and Solutions

Issue: Votes not being recorded

Solutions:

  • Check database connection
  • Verify voter authentication is working
  • Review application logs for errors
  • Ensure poll is active and accepting votes

Issue: Blockchain verification failing

Troubleshooting:

  • Verify RPC endpoint accessibility
  • Check blockchain network configuration
  • Review smart contract address
  • Check gas multiplier settings
  • Monitor blockchain network status

Issue: Slow poll loading

Solutions:

  • Enable caching
  • Optimize database queries
  • Check system resources
  • Review API response times
  • Consider database indexing

Issue: Email notifications not sending

Solutions:

  • Verify SMTP configuration
  • Check email credentials
  • Review email logs
  • Test SMTP connection
  • Check firewall rules

Upgrading Bitpoll

To update Bitpoll to a newer version:

  1. Update your Dockerfile:

    RUN git clone https://github.com/bitpoll/bitpoll.git . && \
    git checkout latest-version
  2. Commit and push to GitHub

  3. Klutch.sh will automatically rebuild

  4. Always backup database before upgrading

  5. Test in development first

  6. Monitor logs after upgrade

Use Cases

Organization Surveys

  • Employee feedback and engagement
  • Customer satisfaction surveys
  • Product feature voting
  • Priority decision-making

Community Governance

  • Proposal voting
  • Budget allocation
  • Leadership elections
  • Policy decisions

Research and Data Collection

  • Academic surveys
  • Market research
  • Opinion polling
  • Behavioral studies

DAOs and Blockchain Projects

  • Governance voting
  • Treasury allocation
  • Protocol upgrades
  • Community initiatives

Additional Resources

Conclusion

Deploying Bitpoll on Klutch.sh provides you with a secure, transparent, and blockchain-verified polling platform that maintains complete control over your voting infrastructure. With comprehensive poll configuration options, real-time result analysis, blockchain verification for vote integrity, and API access for integration, Bitpoll enables organizations and communities to conduct trustworthy voting and surveys. Klutch.sh’s managed infrastructure ensures your polling system is always available, secure, and performant, allowing you to focus on gathering meaningful feedback and making data-driven decisions.

Start hosting transparent, verifiable polls and surveys today by deploying Bitpoll on Klutch.sh and empower your community with decentralized voting.