Putting a 'Save as PDF' link in your protected members area or local intranet site

Our regular Save As PDF Links are meant to quickly let your customers turn your webpages into PDF by adding a simple link to your pages. Though that is a very quick solution for most situations, it won't work in all situations.

For example when you have one of the following situations:

  • Your web pages are on a local intranet and not reachable from the regular internet
  • Your users log into a secure members area and you want them to be able to save their pages as PDF
  • You want to show an "in progress" message when the PDF is generated

For all these situations you can use our API with some simple JavaScript that we will explain below. You can see it in action when you click the button in the "Usage Example" section on the right.

How does it work?

Our HTML to PDF API takes HTML as input and returns a PDF. With the JavaScript below you take the HTML of the webpage that you're on and send it our API. Then our API will return a PDF and the JavaScript will then display it to the user.

Here's the basic code in JavaScript that you should link to the click of your button. You can do this by adding onclick="PDFmyURL()" to your save as PDF button or link. This will work for most scenarios. Please scroll down for the more elaborate scenario that we use ourselves.

<script>
function PDFmyURL() {
	// First we take the HTML of the page
	var html = document.documentElement.outerHTML;
	
	// Now we prepare the data that we pass to the API
	// In this example we want to hide the section with the example so we pass custom CSS
	// Note that you don't need to pass any other parameters if your defaults in the members area are already good
	var data = { html: html, license:'yourlicensekey', css:'#examples { display:none !important;}' };
	var serialized = Object.keys(data).map(function(k) { 
		return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
		}).join('&')
				
	// You can insert an "in progress" message here
	
	// We now prepare the API call
	xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
		var a;
		if (xhttp.readyState === 4 && xhttp.status === 200) {
			// The PDF is now generated
			// You can remove the "in progress" message here
		
			// Now we show the PDF to the user
			a = document.createElement('a');
			a.href = window.URL.createObjectURL(xhttp.response);
			a.download = "example.pdf";
			a.style.display = 'none';
			document.body.appendChild(a);
			a.click();
		}
	};
	
	// This is the actual call to our API
	xhttp.open("POST", "https://pdfmyurl.com/api", true);
	xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
	xhttp.responseType = 'blob';
	xhttp.send(serialized);
}
</script>

A more elaborate scenario if your resources are even more protected

In some situations we will find that just sending the plain HTML is not enough. This can be when the resources on your page are ALSO not accessible from the internet and you didn't inline them.
In that case you can use some of our JavaScript that inlines the resources for you.

Below we explain our own JavaScript, where we:

  1. Make sure we take ALL HTML rather than just the HTML in the first example
  2. Take the stylesheets on the page and inline them in the HTML
  3. Take the images on the page and pass them as data instead of as URLs
  4. Use BootStrap and JQuery to show an "in progress" message

Here's the example with some commenting. Please drop us an email if you need further help implementing this.

<script>
// In this example we show everything so you can copy/paste if you have jQuery & BootStrap

//jQuery is loaded now, now wait for the DOM to be loaded 
$(document).ready(function() { 
	
	$('#pdfbutton').click(function(e) {
		e.preventDefault();
		// The following code is now linked to the PDF button
			
		//let's inline all the stylesheets so they don't need to be downloadedable
		sheets = document.styleSheets;
		var css = '';
		for(var c = 0; c < sheets.length; c++) {
			for (var d = 0; d < sheets[c].cssRules.length ; d++) {
				css = css + sheets[c].cssRules[d].cssText;
			}
		}

		var head = document.head, style = document.createElement('style');

		style.type = 'text/css';
		if (style.styleSheet){
			style.styleSheet.cssText = css;
		} else {
			style.appendChild(document.createTextNode(css));
		}

		head.appendChild(style);

		// now we might as well remove the stylesheets
		var elements = document.querySelectorAll('link[rel=stylesheet]');
		for(var i=0;i<elements.length;i++){
			elements[i].parentNode.removeChild(elements[i]);
		}

		// let's convert all images to data so they don't need to be downloadable  	
		function setBase64Image(img) {
			var canvas = document.createElement("canvas");
			canvas.width = img.width;
			canvas.height = img.height;
			var ctx = canvas.getContext("2d");
			ctx.drawImage(img, 0, 0);
			var dataURL = canvas.toDataURL("image/png");
			img.src = dataURL;
				
		}

		var images = document.getElementsByTagName("img");
		if (images.length > 0) {
			for (var j=0; j<images.length; j++ ) {
				setBase64Image(images[j]);
			}
		}

		// now we'll take ALL HTML including the doctype
		var html = '', node = document.firstChild;
		while (node) {
			switch (node.nodeType) {
				case Node.ELEMENT_NODE:
					html += node.outerHTML;
					break;
				case Node.TEXT_NODE:
					html += node.nodeValue;
					break;
				case Node.CDATA_SECTION_NODE:
					html += '<![CDATA[' + node.nodeValue + ']]>';
					break;
				case Node.COMMENT_NODE:
					html += '<!--' + node.nodeValue + '-->';
					break;
				case Node.DOCUMENT_TYPE_NODE:
					// (X)HTML documents are identified by public identifiers
					html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
					break;
			}
			node = node.nextSibling;
		}	    	

		var data = { html: html, license:'yourlicensekey', css:'#examples { display:none !important;}' };
		// You can pass all the parameters you like if you want, in this example we want to hide the section with the example
		// Note that you don't need to pass any other parameters if your defaults in the members area are already good

		// we will show an in progress message with a BootStrap modal
		$('#inProgress').modal('show');
			
		xhttp = new XMLHttpRequest();
		xhttp.onreadystatechange = function() {
			var a;
			if (xhttp.readyState === 4 && xhttp.status === 200) {
				// the PDF is ready so we remove the in progress message
				$('#inProgress').modal('hide');

				// and show the PDF
				a = document.createElement('a');
				a.href = window.URL.createObjectURL(xhttp.response);
				a.download = "example.pdf";
				a.style.display = 'none';
				document.body.appendChild(a);
				a.click();
			}
		};
		
		xhttp.open("POST", "https://pdfmyurl.com/api", true);
		xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		xhttp.responseType = 'blob';
		xhttp.send($.param( data ));
	});
}); 
</script>