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
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.
Network Latency: CraftMyPDF's own documentation states 1.5-30 seconds per PDF. IronPDF generates locally in milliseconds.
Per-PDF Costs Add Up: 10,000 PDFs/month at subscription rates creates significant recurring costs versus a one-time perpetual license.
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.
- 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" .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 IronPdfStep 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;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";Complete API Migration Reference
API Endpoint Mapping
| CraftMyPDF | IronPDF | Notes |
|---|---|---|
POST /v1/create | renderer.RenderHtmlAsPdf(html) | No API call needed |
X-API-KEY header | License.LicenseKey = "..." | Set once at startup |
template_id | Standard HTML string | Use any HTML |
{%name%} placeholders | $"{name}" C# interpolation | Standard .NET |
POST /v1/merge | PdfDocument.Merge(pdfs) | Local, instant |
POST /v1/add-watermark | pdf.ApplyWatermark(html) | HTML-based |
| Webhook callbacks | Not needed | Results are synchronous |
| Rate limiting | Not applicable | No limits |
Configuration Mapping
| CraftMyPDF Option | IronPDF Equivalent | Notes |
|---|---|---|
template_id | HTML string | Use your own HTML |
data JSON | C# interpolation | $"Hello {name}" |
page_size: "A4" | PaperSize = PdfPaperSize.A4 | |
orientation: "landscape" | PaperOrientation = Landscape | |
margin_top: 20 | MarginTop = 20 | In millimeters |
header | HtmlHeader | Full HTML support |
footer | HtmlFooter | Full HTML support |
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);
}
}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");
}
}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);
}
}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");
}
}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);
}
}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");
}
}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
}
});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);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);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!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!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);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.






