Skip to footer content
MIGRATION GUIDES

How to Migrate from CraftMyPDF to IronPDF in C#

Why Migrate from CraftMyPDF to IronPDF?

Cloud-based PDF APIs like CraftMyPDF introduce fundamental issues that make them unsuitable for many production environments.

The Problem with Cloud-Based PDF APIs

  1. Your Data Leaves Your System: Every HTML template and JSON data payload is transmitted to CraftMyPDF's servers. For invoices, contracts, medical records, or any sensitive business data, this creates HIPAA, GDPR, and SOC2 compliance risks.

  2. Network Latency: CraftMyPDF's own documentation states 1.5-30 seconds per PDF. IronPDF generates locally in milliseconds.

  3. Per-PDF Costs Add Up: 10,000 PDFs/month at subscription rates creates significant recurring costs versus a one-time perpetual license.

  4. Print-Optimized Output: Cloud APIs often optimize for print—reducing backgrounds and simplifying colors to save "ink." The result never looks like your HTML on screen.

  5. Template Lock-In: CraftMyPDF requires their proprietary drag-and-drop editor. You cannot use standard HTML/CSS freely.

Architecture Comparison

Aspect CraftMyPDF IronPDF
Data Location Cloud (your data leaves your system) On-premise (data never leaves)
Latency 1.5-30 seconds per PDF Milliseconds
Pricing Per-PDF subscription One-time perpetual license
Template System Proprietary drag-and-drop only Any HTML/CSS/JavaScript
Output Quality Print-optimized Pixel-perfect screen rendering
Works Offline No (requires internet) Yes
Compliance Data leaves organization SOC2/HIPAA friendly

Feature Comparison

Feature CraftMyPDF IronPDF
HTML to PDF Via API templates ✅ Native
URL to PDF Via API ✅ Native
Custom templates Proprietary editor only ✅ Any HTML
CSS3 support Limited ✅ Full
JavaScript rendering Limited ✅ Full
Merge/Split PDFs Via API ✅ Native
Watermarks Via API ✅ Native
Works offline
Self-hosted

Pre-Migration Preparation

Prerequisites

Ensure your environment meets these requirements:

  • .NET Framework 4.6.2+ or .NET Core 3.1 / .NET 5-9
  • Visual Studio 2019+ or VS Code with C# extension
  • NuGet Package Manager access
  • IronPDF license key (free trial available at ironpdf.com)

Audit CraftMyPDF Usage

Run these commands in your solution directory to identify all CraftMyPDF references:

# Find all CraftMyPDF usages in your codebase
grep -r "CraftMyPdf\|craftmypdf\|api.craftmypdf.com" --include="*.cs" .
grep -r "X-API-KEY" --include="*.cs" .

# Find API key references
grep -r "your-api-key\|template-id\|template_id" --include="*.cs" .

# Find NuGet package references
grep -r "CraftMyPdf\|RestSharp" --include="*.csproj" .
# Find all CraftMyPDF usages in your codebase
grep -r "CraftMyPdf\|craftmypdf\|api.craftmypdf.com" --include="*.cs" .
grep -r "X-API-KEY" --include="*.cs" .

# Find API key references
grep -r "your-api-key\|template-id\|template_id" --include="*.cs" .

# Find NuGet package references
grep -r "CraftMyPdf\|RestSharp" --include="*.csproj" .
SHELL

Breaking Changes to Anticipate

Change CraftMyPDF IronPDF Impact
Architecture Cloud REST API Local .NET library Remove HTTP calls
Templates Proprietary editor Standard HTML Convert templates to HTML
API Key Required for every call License at startup Remove API key handling
Async pattern Required (HTTP) Optional Remove await if preferred
Error handling HTTP status codes Exceptions Change try/catch patterns
Data binding JSON templates String interpolation Simplify data binding

Step-by-Step Migration Process

Step 1: Update NuGet Packages

Remove the HTTP client library and install IronPDF:

# Remove RestSharp HTTP client
dotnet remove package RestSharp

# Install IronPDF
dotnet add package IronPdf
# Remove RestSharp HTTP client
dotnet remove package RestSharp

# Install IronPDF
dotnet add package IronPdf
SHELL

Step 2: Update Namespace References

Replace HTTP client namespaces with IronPDF:

// Remove these
using RestSharp;
using System.IO;

// Add this
using IronPdf;
// Remove these
using RestSharp;
using System.IO;

// Add this
using IronPdf;
Imports IronPdf
$vbLabelText   $csharpLabel

Step 3: Configure License (Once at Startup)

Replace per-request API key headers with a single license configuration:

// Add at application startup (Program.cs or Global.asax)
// This replaces all X-API-KEY headers
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Global.asax)
// This replaces all X-API-KEY headers
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Global.asax)
' This replaces all X-API-KEY headers
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Complete API Migration Reference

API Endpoint Mapping

CraftMyPDF IronPDF
POST /v1/create renderer.RenderHtmlAsPdf(html)
X-API-KEY header License.LicenseKey = "..."
template_id Standard HTML string
{%name%} placeholders $"{name}" C# interpolation
POST /v1/merge PdfDocument.Merge(pdfs)
POST /v1/add-watermark pdf.ApplyWatermark(html)
Webhook callbacks Not needed
Rate limiting Not applicable

Configuration Mapping

CraftMyPDF Option IronPDF Equivalent
template_id HTML string
data JSON C# interpolation
page_size: "A4" PaperSize = PdfPaperSize.A4
orientation: "landscape" PaperOrientation = Landscape
margin_top: 20 MarginTop = 20
header HtmlHeader
footer HtmlFooter

Code Migration Examples

HTML to PDF Conversion

The most common operation demonstrates the fundamental architecture shift from cloud API to local rendering.

CraftMyPDF Implementation:

// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                html = "<h1>Hello World</h1><p>This is a PDF from HTML</p>"
            }
        });

        var response = client.Execute(request);
        File.WriteAllBytes("output.pdf", response.RawBytes);
    }
}
// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                html = "<h1>Hello World</h1><p>This is a PDF from HTML</p>"
            }
        });

        var response = client.Execute(request);
        File.WriteAllBytes("output.pdf", response.RawBytes);
    }
}
Imports System
Imports RestSharp
Imports System.IO

Module Program
    Sub Main()
        Dim client As New RestClient("https://api.craftmypdf.com/v1/create")
        Dim request As New RestRequest(Method.POST)
        request.AddHeader("X-API-KEY", "your-api-key")
        request.AddJsonBody(New With {
            .template_id = "your-template-id",
            .data = New With {
                .html = "<h1>Hello World</h1><p>This is a PDF from HTML</p>"
            }
        })

        Dim response = client.Execute(request)
        File.WriteAllBytes("output.pdf", response.RawBytes)
    End Sub
End Module
$vbLabelText   $csharpLabel

IronPDF Implementation:

// NuGet: Install-Package IronPdf
using System;
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML</p>");
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using System;
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML</p>");
        pdf.SaveAs("output.pdf");
    }
}
Imports System
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML</p>")
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF eliminates the RestClient setup, API key headers, template IDs, and HTTP response handling—reducing a 15-line cloud operation to 4 lines of local code. For more options, see the HTML to PDF documentation.

URL to PDF Conversion

CraftMyPDF Implementation:

// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                url = "https://example.com"
            },
            export_type = "pdf"
        });

        var response = client.Execute(request);
        File.WriteAllBytes("webpage.pdf", response.RawBytes);
    }
}
// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                url = "https://example.com"
            },
            export_type = "pdf"
        });

        var response = client.Execute(request);
        File.WriteAllBytes("webpage.pdf", response.RawBytes);
    }
}
Imports System
Imports RestSharp
Imports System.IO

Module Program
    Sub Main()
        Dim client As New RestClient("https://api.craftmypdf.com/v1/create")
        Dim request As New RestRequest(Method.POST)
        request.AddHeader("X-API-KEY", "your-api-key")
        request.AddJsonBody(New With {
            .template_id = "your-template-id",
            .data = New With {
                .url = "https://example.com"
            },
            .export_type = "pdf"
        })

        Dim response = client.Execute(request)
        File.WriteAllBytes("webpage.pdf", response.RawBytes)
    End Sub
End Module
$vbLabelText   $csharpLabel

IronPDF Implementation:

// NuGet: Install-Package IronPdf
using System;
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using System;
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
Imports System
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
        pdf.SaveAs("webpage.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF's RenderUrlAsPdf method captures the complete webpage including JavaScript-rendered content. For more options, see the URL to PDF documentation.

Headers and Footers

CraftMyPDF Implementation:

// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                html = "<h1>Document Content</h1>",
                header = "<div>Page Header</div>",
                footer = "<div>Page {page} of {total_pages}</div>"
            }
        });

        var response = client.Execute(request);
        File.WriteAllBytes("document.pdf", response.RawBytes);
    }
}
// NuGet: Install-Package RestSharp
using System;
using RestSharp;
using System.IO;

class Program
{
    static void Main()
    {
        var client = new RestClient("https://api.craftmypdf.com/v1/create");
        var request = new RestRequest(Method.POST);
        request.AddHeader("X-API-KEY", "your-api-key");
        request.AddJsonBody(new
        {
            template_id = "your-template-id",
            data = new
            {
                html = "<h1>Document Content</h1>",
                header = "<div>Page Header</div>",
                footer = "<div>Page {page} of {total_pages}</div>"
            }
        });

        var response = client.Execute(request);
        File.WriteAllBytes("document.pdf", response.RawBytes);
    }
}
Imports System
Imports RestSharp
Imports System.IO

Module Program
    Sub Main()
        Dim client As New RestClient("https://api.craftmypdf.com/v1/create")
        Dim request As New RestRequest(Method.POST)
        request.AddHeader("X-API-KEY", "your-api-key")
        request.AddJsonBody(New With {
            .template_id = "your-template-id",
            .data = New With {
                .html = "<h1>Document Content</h1>",
                .header = "<div>Page Header</div>",
                .footer = "<div>Page {page} of {total_pages}</div>"
            }
        })

        Dim response = client.Execute(request)
        File.WriteAllBytes("document.pdf", response.RawBytes)
    End Sub
End Module
$vbLabelText   $csharpLabel

IronPDF Implementation:

// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.TextHeader = new TextHeaderFooter()
        {
            CenterText = "Page Header"
        };
        renderer.RenderingOptions.TextFooter = new TextHeaderFooter()
        {
            CenterText = "Page {page} of {total-pages}"
        };

        var pdf = renderer.RenderHtmlAsPdf("<h1>Document Content</h1>");
        pdf.SaveAs("document.pdf");
    }
}
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.TextHeader = new TextHeaderFooter()
        {
            CenterText = "Page Header"
        };
        renderer.RenderingOptions.TextFooter = new TextHeaderFooter()
        {
            CenterText = "Page {page} of {total-pages}"
        };

        var pdf = renderer.RenderHtmlAsPdf("<h1>Document Content</h1>");
        pdf.SaveAs("document.pdf");
    }
}
Imports System
Imports IronPdf
Imports IronPdf.Rendering

Module Program
    Sub Main()
        Dim renderer = New ChromePdfRenderer()
        renderer.RenderingOptions.TextHeader = New TextHeaderFooter() With {
            .CenterText = "Page Header"
        }
        renderer.RenderingOptions.TextFooter = New TextHeaderFooter() With {
            .CenterText = "Page {page} of {total-pages}"
        }

        Dim pdf = renderer.RenderHtmlAsPdf("<h1>Document Content</h1>")
        pdf.SaveAs("document.pdf")
    End Sub
End Module
$vbLabelText   $csharpLabel

IronPDF supports placeholder tokens like {page} and {total-pages} for dynamic page numbering. For more options, see the headers and footers documentation.

Template Variable Conversion

CraftMyPDF uses proprietary template placeholders that must be converted to C# string interpolation:

CraftMyPDF Pattern:

// CraftMyPDF template variables
request.AddJsonBody(new
{
    template_id = "invoice-template",
    data = new
    {
        customer = "John Doe",
        amount = "$1,000",
        items = invoiceItems
    }
});
// CraftMyPDF template variables
request.AddJsonBody(new
{
    template_id = "invoice-template",
    data = new
    {
        customer = "John Doe",
        amount = "$1,000",
        items = invoiceItems
    }
});
$vbLabelText   $csharpLabel

IronPDF Pattern:

// C# string interpolation
var html = $@"
<html>
<body>
    <h1>Invoice</h1>
    <p>Customer: {customerName}</p>
    <p>Amount: {amount}</p>
    {GenerateItemsTable(invoiceItems)}
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
// C# string interpolation
var html = $@"
<html>
<body>
    <h1>Invoice</h1>
    <p>Customer: {customerName}</p>
    <p>Amount: {amount}</p>
    {GenerateItemsTable(invoiceItems)}
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
Dim html As String = $"
<html>
<body>
    <h1>Invoice</h1>
    <p>Customer: {customerName}</p>
    <p>Amount: {amount}</p>
    {GenerateItemsTable(invoiceItems)}
</body>
</html>"

Dim pdf = renderer.RenderHtmlAsPdf(html)
$vbLabelText   $csharpLabel

Critical Migration Notes

Remove All HTTP Code

The most significant change is eliminating network dependencies. IronPDF runs locally—no RestClient, no API calls, no response handling:

// CraftMyPDF - HTTP required
var client = new RestClient("https://api.craftmypdf.com/v1/create");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "your-api-key");
var response = await client.ExecuteAsync(request);

// IronPDF - no HTTP
var pdf = renderer.RenderHtmlAsPdf(html);
// CraftMyPDF - HTTP required
var client = new RestClient("https://api.craftmypdf.com/v1/create");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "your-api-key");
var response = await client.ExecuteAsync(request);

// IronPDF - no HTTP
var pdf = renderer.RenderHtmlAsPdf(html);
$vbLabelText   $csharpLabel

Remove Rate Limiting Code

CraftMyPDF imposes API rate limits requiring retry logic. IronPDF has no limits:

// CraftMyPDF - needed to avoid 429 errors
await Task.Delay(100);
if (response.StatusCode == TooManyRequests) { /* retry */ }

// IronPDF - no limits, just generate
var pdf = renderer.RenderHtmlAsPdf(html);
// Remove all rate limit code!
// CraftMyPDF - needed to avoid 429 errors
await Task.Delay(100);
if (response.StatusCode == TooManyRequests) { /* retry */ }

// IronPDF - no limits, just generate
var pdf = renderer.RenderHtmlAsPdf(html);
// Remove all rate limit code!
$vbLabelText   $csharpLabel

Remove Webhook Handlers

CraftMyPDF uses async webhooks for PDF completion. IronPDF is synchronous—the PDF is ready immediately:

// CraftMyPDF - webhook callback required
// POST with webhook_url, wait for callback

// IronPDF - PDF ready immediately
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// No callback needed!
// CraftMyPDF - webhook callback required
// POST with webhook_url, wait for callback

// IronPDF - PDF ready immediately
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// No callback needed!
$vbLabelText   $csharpLabel

Sync by Default

Remove async/await patterns if they were only needed for HTTP calls:

// CraftMyPDF - async required
var response = await client.ExecuteAsync(request);

// IronPDF - sync by default (async available if needed)
var pdf = renderer.RenderHtmlAsPdf(html);
// CraftMyPDF - async required
var response = await client.ExecuteAsync(request);

// IronPDF - sync by default (async available if needed)
var pdf = renderer.RenderHtmlAsPdf(html);
$vbLabelText   $csharpLabel

Post-Migration Checklist

After completing the code migration, verify the following:

  • Run all PDF generation tests
  • Compare output quality (IronPDF's Chromium engine renders pixel-perfect)
  • Measure performance improvement (milliseconds vs. seconds)
  • Verify all templates converted correctly
  • Test batch processing without rate limits
  • Test in all target environments
  • Update CI/CD pipelines
  • Cancel CraftMyPDF subscription
  • Remove API key from secrets/config

Future-Proofing Your PDF Infrastructure

With .NET 10 on the horizon and C# 14 introducing new language features, choosing a local PDF library eliminates cloud API deprecation risks and version compatibility concerns. IronPDF's perpetual licensing model means your migration investment pays dividends indefinitely as projects extend into 2025 and 2026—without recurring subscription costs or data leaving your infrastructure.

Additional Resources


Migrating from CraftMyPDF to IronPDF eliminates cloud dependencies, network latency, per-PDF costs, and template lock-in while delivering pixel-perfect Chromium rendering that runs offline. The transition from REST API calls to local method invocations simplifies your codebase and keeps sensitive document data within your infrastructure.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me